views:

1491

answers:

9

I've been trying to get into F# on and off for a while but I keep getting put off. Why?

Because no matter which 'beginners' resource I try to look at I see very simple examples that start using the operator ->.

However, nowhere have I found as yet that provides a clear simple explanation of what this operator means. It's as though it must be so obvious that it doesn't need explanation even to complete newbies.

I must therefore be really dense or perhaps it's nearly 3 decades of previous experience holding me back.

Can someone please, explain it or point to a truly accessible resource that explains it?

+11  A: 

It basically means "maps to". Read it that way or as "is transformed into" or something like that.

So, from the F# in 20 minutes tutorial,

> List.map (fun x -> x % 2 = 0) [1 .. 10];;
val it : bool list
= [false; true; false; true; false; true; false; true; false; true]

The code (fun i -> i % 2 = 0) defines an anonymous function, called a lambda expression, that has a parameter x and the function returns the result of "x % 2 = 0", which is whether or not x is even.

Blair Conrad
Can also use this reference: http://research.microsoft.com/fsharp/manual/lexyacc.aspx
Arthur Thomas
+1  A: 

From Microsoft:

Function types are the types given to first-class function values and are written int -> int. They are similar to .NET delegate types, except they aren't given names. All F# function identifiers can be used as first-class function values, and anonymous function values can be created using the (fun ... -> ...) expression form.

Brettski
+3  A: 

(a -> b) means "function from a to b". In type annotation, it denotes a function type. For example, f : (int -> String) means that f refers to a function that takes an integer and returns a string. It is also used as a contstructor of such values, as in

val f : (int -> int) = fun n -> n * 2

which creates a value which is a function from some number n to that same number multiplied by two.

Apocalisp
+1  A: 

The nice thing about languages such as Haskell (it's very similar in F#, but I don't know the exact syntax -- this should help you understand ->, though) is that you can apply only parts of the argument, to create curried functions:

adder n x y = n + x + y

In other words: "give me three things, and I'll add them together". When you throw numbers at it, the compiler will infer the types of n x and y. Say you write

adder 1 2 3

The type of 1, 2 and 3 is Int. Therefore:

adder :: Int -> Int -> Int -> Int

That is, give me three integers, and I will become an integer, eventually, or the same thing as saying:

five :: Int
five = 5

But, here's the nice part! Try this:

add5 = adder 5

As you remember, adder takes an int, an int, an int, and gives you back an int. However, that is not the entire truth, as you'll see shortly. In fact, add5 will have this type:

add5 :: Int -> Int -> Int

It will be as if you have "peeled off" of the integers (the left-most), and glued it directly to the function. Looking closer at the function signature, we notice that the -> are right-associative, i.e.:

addder :: Int -> (Int -> (Int -> Int))

This should make it quite clear: when you give adder the first integer, it'll evaluate to whatever's to the right of the first arrow, or:

add5andtwomore :: Int -> (Int -> Int)
add5andtwomore = adder 5

Now you can use add5andtwomore instead of "adder 5". This way, you can apply another integer to get (say) "add5and7andonemore":

add5and7andonemore :: Int -> Int
add5and7andonemore = adder 5 7

As you see, add5and7andonemore wants exactly another argument, and when you give it one, it will suddenly become an integer!

  > add5and7andonemore 9
 => ((add5andtwomore) 7) 9
 => ((adder 5) 7) 9)
<=> adder 5 7 9

Substituting the parameters to adder (n x y) for (5 7 9), we get:

  > adder 5 7 9 = 5 + 7 + 9
 => 5 + 7 + 9
 => 21

In fact, plus is also just a function that takes an int and gives you back another int, so the above is really more like:

  > 5 + 7 + 9
 => (+ 5 (+ 7 9))
 => (+ 5 16)
 => 21

There you go!

Mikael Jansson
+1  A: 

There are plenty of great answers here already, I just want to add to the conversation another way of thinking about it.

' -> ' means function.

'a -> 'b is a function that takes an 'a and returns a 'b

('a * 'b) -> ('c * 'd) is a function that takes a tuple of type ('a, 'b) and returns a tuple of ('c, 'd). Such as int/string returns float/char.

Where it gets interesting is in the cascade case of 'a -> 'b -> 'c. This is a function that takes an 'a and returns a function ('b -> 'c), or a function that takes a 'b -> 'c.

So if you write: let f x y z = ()

The type will be f : 'a -> 'b -> 'c -> unit, so if you only applied the first parameter, the result would be a curried function 'b -> 'c -> 'unit.

Chris Smith
+1  A: 

In the context of defining a function, it is similar to => from the lambda expression in C# 3.0.

F#: let f = fun x -> x*x
C#: Func<int, int> f = x => x * x;

The -> in F# is also used in pattern matching, where it means: if the expression matches the part between | and ->, then what comes after -> should be given back as the result:

let isOne x = match x with
 | 1 -> true
 | _ -> false
Michiel Borkent
+7  A: 

First question - are you familiar with lambda expressions in C#? If so the -> in F# is the same as the => in C# (I think you read it 'goes to').

The -> operator can also be found in the context of pattern matching

match x with
| 1 -> dosomething
| _ -> dosomethingelse

I'm not sure if this is also a lambda expression, or something else, but I guess the 'goes to' still holds.

Maybe what you are really referring to is the F# parser's 'cryptic' responses:

> let add a b = a + b
val add: int -> int -> int

This means (as most of the examples explain) that add is a 'val' that takes two ints and returns an int. To me this was totally opaque to start with. I mean, how do I know that add isn't a val that takes one int and returns two ints?

Well, the thing is that in a sense, it does. If I give add just one int, I get back an (int -> int):

> let inc = add 1
val inc: int -> int

This (currying) is one of the things that makes F# so sexy, for me.

For helpful info on F#, I have found that blogs are FAR more useful that any of the official 'documentation': Here are some names to check out

Benjol
+30  A: 

'->' is not an operator. It appears in the F# syntax in a number of places, and its meaning depends on how it is used as part of a larger construct.

Inside a type, '->' describes function types as people have described above. For example

let f : int -> int = ...

says that 'f' is a function that takes an int and returns an int.

Inside a lambda ("thing that starts with 'fun' keyword"), '->' is syntax that separates the arguments from the body. For example

fun x y -> x + y + 1

is an expression that defines a two argument function with the given implementation.

Inside a "match" construct, '->' is syntax that separates patterns from the code that should run if the pattern is matched. For example, in

match someList with
| [] -> 0
| h::t -> 1

the stuff to the left of each '->' are patterns, and the stuff on the right is what happens if the pattern on the left was matched.

The difficulty in understanding may be rooted in the faulty assumption that '->' is "an operator" with a single meaning. An analogy might be "." in C#, if you have never seen any code before, and try to analyze the "." operator based on looking at "obj.Method" and "3.14" and "System.Collections", you may get very confused, because the symbol has different meanings in different contexts. Once you know enough of the language to recognize these contexts, however, things become clear.

Brian
I've accepted this as the answer because its the closet to a the sort of complete answer I was looking for but there are a number of other details from other answers that help. I'm unconviced that -> is not an operator however. Can anyone else confirm this?
AnthonyWJones
You could say it's a type-level operator. Rather, a datatype constructor. ( a -> b ) is isomorphic to (a, b). The arrow in the former is the same kind of thing as the comma in the latter.
Apocalisp
Apocalisp, it took a couple of readings (you're assumption that I knew waht isomorphic means held me back) but I get it now.
AnthonyWJones
And now in a `for` loop it stands for `do yield` (`[for i in 0..n -> i]`).
Cogwheel - Matthew Orlando
+1  A: 

Many great answers to this questions, thanks people. I'd like to put here an editable answer that brings things together.

For those familiar with C# understanding -> being the same as => lamba expression is a good first step. This usage is :-

fun x y -> x + y + 1

Can be understood as the equivalent to:-

(x, y) => x + y + 1;

However its clear that -> has a more fundemental meaning which stems from concept that a function that takes two parameters such as the above can be reduced (is that the correct term?) to a series of functions only taking one parameter.

Hence when the above is described in like this:-

Int -> Int -> Int

It really helped to know that -> is right associative hence the above can be considered:-

Int -> (Int -> Int)

Aha! We have a function that takes Int and returns (Int -> Int) (a curried function?).

The explaination that -> can also appear as part of type definiton also helped. (Int -> Int) is the type of any of function which takes an Int and returns an Int.

Also helpful is the -> appears in other syntax such as matching but there it doesn't have the same meaning? Is that correct? I'm not sure it is. I suspect it has the same meaning but I don't have the vocabulary to express that yet.

Note the purpose of this answer is not to spawn further answers but to be collaboratively edited by you people to create a more definitive answer. Utlimately it would be good that all the uncertainies and fluf (such as this paragraph) be removed and better examples added. Lets try keep this answer as accessible to the uninitiated as possible.

AnthonyWJones
I'll come back when I've got enough reputation :)
Benjol
So in a type definition - Int -> Int -> Int = a func that takes an int and returns a func that takes an int and returns an int - is that right?
Erik Forbes