> open System.Windows.Forms;;

You already figure out one way of doing it, but you can also define like :

- let c = List.map (fun x-> x+2) [3;13;2];;

> List.iter (fun x -> printf "%d" x) c;;

#you don't need to convert them to string printf has a great formatter that does that.

> c |> List.iter (fun x -> (MessageBox.Show(x.ToString()) |> ignore ))

For messagebox you need to convert it to string ....

:= is assigning a value for reference types. T
let p = ref 5
to reaassing p -> := is used.

p:= 2

By on 1/22/2008 3:34 PM ()

Can,

Thanks again for your help. I tried everything out and I understand it a little better. I had a question about List.map versus List.iter. From the documentation that I've been able to find, it's a little hard to tell them apart. However if I use List.iter instead of List.map(fun x-> x+2) it doesn't work, so it's obvious they're not the same. Can you help me to understand how they differ?

I'm also confused about how List.iter works as both an infix function and a prefix function. In your printf example you seem to use it with 2 arguments. In your MessageBox example, you pipe a value into it with the 1st argument following List.iter. I could use some help understanding that as well.

Are you doing your work from within Visual Studio or are you running programs from the command line?

Thanks again for all of your help, it's a lot easier than going it alone.

Mitchell

By on 1/23/2008 1:21 PM ()

Hi Mitchell,

Map function returns a new list. It means that the anonymous function you pass should return a single value of that type.

let c = List.map (fun x-> x+2) [3;13;2];;

The anonymous function passed returns an integer.

Iter function returns unit. Both iter samples are same as previously explained in this thread by zakaluka. it takes a function and the list itself.

> c |> List.iter (fun x -> (MessageBox.Show(x.ToString()) |> ignore ))

> List.iter (fun x -> (MessageBox.Show(x.ToString()) |> ignore )) c

But the second one needs some more type information, that's why the first one is used.

For some quick code I use the interactive window, and Visual Studio for everything else.

Hope this helps.

By on 1/24/2008 2:34 AM ()

Can,

Thanks for the help. I must confess that I'm still not entirely clear on the difference, but at this point I just need to work through it myself for a while. I'm sure in a few days I'll bother you guys with some more questions, on a new thread.

Thanks so much. It's an amazing thing that there are people like you out there who are willing and able to help those of us who are trying to get on board.

Mitchell

By on 1/24/2008 11:47 AM ()

Can,

Thank you. I still have to give it a try. I've been doing this within VS 2005. I presume that the ";;" is not needed there.

Can you tell me what the "%d" is for?

Is the "|" for piping? Then, is the ">" that follows because you're running from a command line? Does the "ignore" allow me to not have to worry that MessageBox wants to return a value?

With regard to the reference types, are they like mutable variables?

I realize that I will find the answers to some of the above questions once I go back in and code a few examples, but I figure as long as I'm writing back I might as well ask.

I really appreciate the help. I think getting started is going to take a little while.

Mitchell

By on 1/22/2008 6:40 PM ()

Welcome to F#. I'll try and answer in order:

(1) At the top of each source file for F#, I would recommend putting in the compiler directive #light. It will eliminate the need to use ;; in the code. It seems more and more likely that the light syntax will end up being the default F# syntax, and it is whitespace dependent. In addition, the majority of the code you see posted or in books is written using light syntax.

(2) Unlike C#, F#'s printf can take arguments of many types without them being converted to strings. However, the flip side is that F# does not automatically run .ToString() or any other function on arguments. Thus, when specifying the output format, you must tell printf what type of argument to expect. In this case, "%d" tells printf to expect an integer (s/byte, u/int16, u/int32, u/int64, u/nativeint). Some other flags for printf are %f (floating-point type), %O (will box the value, ie, upcast it to an System.Object, then run .ToString() on it), and %A (will run the F# function any_to_string on the argument). I would recommend %A if you are not sure what to use.

So, an example would be printf "%s is a string, %d is an int, %A is some type" "What the hell" 58 [1; 2; 3];;. The benefit of using a type-specific flag is that the compiler will throw an exception if you pass in the wrong argument type. This can help if you are trying to debug your code and can't find the problem.

(3) The |> operator is kind of like piping. Take the following example:

Function1(Function2(Function3(Function4(Function5(myarg)))))

I've often written something like that in C++ and Java. The |> operator lets you rewrite the above line backwards, to greatly improve readability. So, in F#, this would be:

myarg |> Function5 |> Function4 |>Function3 |> Function2 |> Function1

As you've probably guessed, it takes the result from each "step" and sends it to be next step. When evaluating functions in this manner, the result from each step becomes the last argument for the next step's function. Here is a real example of what I mean (being used in my code right now, although simplified for this example):

1
2
3
4
{ 2 .. 10 }
|> Seq.map (fun x -> x + 1)
|> Set.of_seq
|> Set.max_elt

If you look through the F# API, you will notice that it is designed specifically to use this style of programming. So, functions take in the results of other functions (from the same module) as their last argument, so that values may be passed in a chain with minimum use of parentheses and nesting.

(4) Basically, yes, reference types are mutable variables. Their syntax is as follows:

1
2
3
let x = ref 5.5 //declaration of reference variable
let y = !x //"getting" the value (y = 5.5)
x := 10.5 + !x //"setting" the value (x = 16.0)

After each statement in the F# interpreter (fsi), you should check the value of the variable to understand what is going on. For example, y's type is float = 7.0, as expected. However, x's type is float ref = {contents = 10.5;}, telling you that it is not just a regular float, but an indirect value that is storing a float (kind of like a pointer).

BTW, if you really want to learn F#, I strongly recommend picking up Robert Pickering's Foundations of F# or Don Syme's Expert F#.

Don't be afraid to ask if you have more questions.

Regards,

z.

By on 1/22/2008 11:43 PM ()

z,

I'm starting to get it a little. I took what you explained and did it this way:

let inc2 x = x + 2
let z = [3;12]

z |> List.map inc2
|> List.map Int32.to_string
|> String.concat " "
|> MessageBox.Show

Then I tried: (unsuccessfully)

let z = [3;12]
z |> List.map Int32.to_string
|> String.concat " "
|> q

The compiler was very unhappy with "q" -- I hadn't declared it. 2 questions on this:
Is this sort of construct a typical way to move the value into a variable?
If so, how do you declare it ahead of time?

Another couple of questions based on Visual Studio:

I'm doing all of this in VS. If I just do a "printf" the values appear in some console window and then disappear before I can even see them. So I've been showing a form at the end of the program to keep the console window open until I close the form. Doesn't seem like the best way. Is there either another way to keep the window open, or is there a way to get the output to show up in the Output Window in Visual Studio?

I ordered one of the books you suggested – Expert F# by Syme. The reviews on Amazon about the readability of Pikering's book scared me away. What do you think?

From what you've heard are most people trying this out in Visual Studio or are they staying with the interactive console?

Thanks again for your invaluable help!

Mitchell

By on 1/23/2008 1:13 PM ()

Before answering some of your more in-depth questions, a note on the environment.

If you installed VS 2005, then F# 1.9.x, then do the following. Open up your F# project/file. Then, go to Tools -> Add-In Manager. Check the add-in that says "F# Interactive for Visual Studio" (check the box on the left, leave the others the way they are). Hit OK. This will bring up a box that is running an F# interpreter.

The way most functional languages work is that they give you a REPL (real-eval-print loop). What this interactive interface lets you do is dynamically test out pieces of code before integrating them into your larger project. Sort of like on-the-spot unit testing. Now, whenever you want to run some code, select the code in the editor and hit ALT+ENTER. This will send the code to the interpreter to be evaluated and the result will be printed right in front of you. The code is sent as a block, ie, send a function as a whole, don't send each line one at a time. Check out the following for more information:

[link:img99.imageshack.us] (this is a vertical panorama of VS 2008 screenshots. Note that you may have different boxes checked in VS 2005 (probably, command-line will be checked). Don't touch any of those settings, only check the box on the left).

My next piece of advice is to forget about Windows Forms (MessageBox, etc), as these elements add unnecessary complexity to learning F#.

Now, onto your questions:

(1) The assignment to 'q' failed, and rightly so. This syntax that I described is not for assigning values to variables (although it can be used as such).

The first thing I feel I need to clarify is that regular assignments using let (eg, let x = 5) are not variable assignments. The value of x cannot be changed in the sense that it can be changed in imperative languages (C++/Java/C#). As such, you can modify your code as follows to assign a value to a variable 'q':

1
2
3
4
let z = [3;12]
let q = z
        |> List.map Int32.to_string
        |> String.concat " "

Just keep in mind that since #light syntax is whitespace-dependent, it matters where the |> are aligned.

(2) If you use the interpreter I describe above, you don't even need to use printf/n. Instead, the REPL will simply output the answer in semi-human readable form.

The way I normally develop is I write a function encompassing an algorithm, then test it with fringle values and incorrect values, knowing what answer I should get. If I don't get what I want, I read through the code a few times till I find the problem. Then, once I'm satisfied, I insert the code into the main project. Then, I do some very preliminary integration testing, ie, checking to see that the functions that need to use the new code are using it correctly and that all pre/post conditions are okay.

(3) About the books, I have Foundations of F# but not Expert F#, and I don't have a problem with it. I don't think you can go wrong with either one, although since I don't have Expert F# I can't really say whether it is appropriate for a person just learning about functional programming. Foundations of F# is very good as an introductory text for functional programming in general and specifically F#.

(4) (from post 4643) List.iter vs. List.map. Think of List.map as transforming each element of a list separately, then combining all those results to make a new list. So, for example, List.map (fun x -> x + 5) [3; 12] will output a new list of the same length:

1
2
> List.map (fun x -> x + 5) [3; 12] ;;
val it : int list = [8; 17]

On the other hand, List.iter is more for imperative style programming. What it does is run the function you provide on each member of the list (similar to List.map). However, it differs in that the return value of the function must be unit, ie, () (unit is equivalent to void in other languages). What this means is that your function cannot return a meaningful value. So, one way I might use List.iter is List.iter (fun x -> printfn "The value is: %A" x) [3; 12]. The output for this line is as follows:

1
2
3
4
> List.iter (fun x -> printfn "The value is: %A" x) [3; 12];;
The value is: 3
The value is: 12
val it : unit = ()

Notice the difference in return values from the two functions. List.iter returns nothing meaningful, which means that all of its work is done through side-effects, ie, some kind of mutability, IO, etc. On the other hand, List.map is mainly for transforming values in a list (usually with no side effects).

Hope I didn't confuse you too much.

Regards,

z.

By on 1/24/2008 2:35 AM ()

z,

Thanks for the information. I think I'm now using Visual Studio more effectively. I have to work through some of the things you explained by myself now. Oh, I found chapter 3 of Pickering's book on line. It looks good! I guess I shouldn't have been put off by the less than positive reviews on Amazon. I'll order it as well.

You haven't confused me, but you did give me a lot to think about. I'll be quiet for a little while (I hope) while going through more of this on my own. I do want to tell you how much I appreciate the fact that you took the time to help me through this part of my learning experience.

I expect to be coming up with new questions, on new threads in the relatively near future. Thanks again.

Mitchell

By on 1/24/2008 11:53 AM ()

Help. I live in a world of vb and excel and I want to replace it all with this. This is a great thread and all of Syme's stuff is great too. Little by little, we'll get there.

By on 1/27/2008 3:34 PM ()

cellbert,

I wonder if we'll be able to replace much of vb and Excel with F#. I'm still to new at it to even know whether I'd like that or not. I wonder about a few things, so far...

Can we write classes in, say, vb, and use them in F#? I'm almost certain the answer is yes, but I guess I'd like to see how that works. Also, how well does the OOP paradigm fit in with the functional paradigm. I guess I'll have to wait until I'm further along to have an opinion.

I wonder about the learning curve for people not oriented toward F# type of programming. If there's a significant difference in the number of people who can eventually code in F# (that is, way less than in vb), then it might not be suitable for most business situations.

Of course I started back in the Fortan days, and OOP along with event driven programming seems way more sophisticated than what was used back then. I'm surprised so many people can do it! Maybe it's a generational thing.

However, I hope you're right and that we (meaning mostly me of course) get there, even little by little.

Mitchell

By on 1/27/2008 7:34 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper