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?
'->' 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.
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.
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
Dustin Campbell (that's diditwith.net, cited in another answer)
Don Symes ('the' man)
Tomasp.net (aka Tomas Petricek)
Andrew Kennedy (for units of measure)
Fsharp.it (famous for the Project Euler solutions)
http://lorgonblog.spaces.live.com/Blog (aka Brian)
Jomo Fisher
(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.
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.
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.
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.
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
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!
Related
I currently have this f# function
let collatz' n =
match n with
| n when n <= 0 -> failwith "collatz' :n is zero or less"
| n when even n = true -> n / 2
| n when even n = false -> 3 * n + 1
Any tips for solving the following problem in F#?
As said in the comments, you need to give a bit more information for any really specific advice, but based on what you have I'll add the following.
The function you have declared satisfies the definition of the Collatz function i.e. even numbers -> n/2 ,and
odd number -> 3n + 1.
So really you only need applyN, let's break it down into its pieces
( `a -> `a) -> `a -> int -> `a list
applyN f n N
That definition is showing you exactly what the function expects.
lets look at f through to N
f -> a function that takes some value of type 'a (in your case likely int) and produces a new value of type 'a.
This corresponds to the function you have already written collatz`
n -> is your seed value. I don't think elaboration is required.
N -> This looks like a maximum amount of steps to go through. In the example posted, if N was larger, you would see a loop [ 1 ;4; 2; 1; 4... ]
and if it was smaller it would stop sooner.
So that is what the function takes and need to do, so how can we achieve this?
I would suggest making use of scan.
The scan function is much like fold, but it returns each interim state in a list.
Another option would be making use of Seq.unfold and then only taking the first few values.
Now, I could continue and give some source code, but I think you should try yourself for now.
When writing a function that can accept currying, you can write it as a single-argument function that returns a function. For example,
let add x =
let inner y = x + y
inner
So you can either do:
add 3 4
or:
let add3 = add 3
add3 4
My question, is because you return a function, you are conceptually calling a function twice (the outer function and the inner function). Is this slower than:
let add x y = x + y
or does the compiler optimise invocations of add 3 4 in the curried definition?
let f x = fun y -> x + y
let g x y = x + y
Looking at these function definitions in dnSpy for an optimized build reveals them to be:
public static int f(int x, int y)
{
return x + y;
}
public static int g(int x, int y)
{
return x + y;
}
This is not that strange because g is actually a short-hand definition for f which is the general case. In F#-like languages function conceptually always take a single value returning a single value. Values might be functions. This is easier to see if one paranthese the function signature for f and g
val f: int -> int -> int
// Actually is
// val f: int -> (int -> int)
// ie f is a function that takes a single int and returns a function that takes a single int and returns an int.
In order to get F# to execute faster on .NET the physical representation of f in an assembly is:
public static int f(int x, int y)
While this is a more natural representation of the F# function.
public static Func<int, int> f(int x)
Would perform poorly though.
Usually F# is clever enough to avoid the overhead of the abstraction by optimization like above and on invocation. However, there are situations where F# can't optimize for you.
Imagine that you are implementing fold
let rec fold f s vs =
match vs with
| v::vs -> fold f (f s v) vs
| [] -> s
Here F# can't fully optimize f s v. The reason is that f might have a more complex implementation than above that might return a different function depending on s.
If you look in dnSpy you note that F# are invoking function using InvokeFast but this does an internal test to see if it can be invoked fast. In fold we then do this test for each value even though this is the same function.
This is the reason one might sometimes see fold written like this:
let fold f s vs =
let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt f
let rec loop s vs =
match vs with
| v::vs -> loop (f.Invoke (s, v)) vs
| [] -> s
loop s vs
Adapt here tests before the loop if f can indeed be optimized and then returns an efficient adapter. In the general case it might still be a bit slower but then this is what the caller intended.
Note; this potential performance degradation doesn't happen for simple function values like 'T -> 'U. This can always be invoked efficiently.
Hope this helps.
I tested this in LINQPad 5.
When compiler optimizations are turned off, the F# compiler will produce different IL for each snippet. In other words, if there are any optimizations going on, it's left up to the JITter, and it may very well be slower to call the first form.
However, when compiler optimizations are turned on, both forms produce identical IL outputs in every scenario I could think of to test it. In fact, with both forms, calling:
add 3 4
yields the IL equivalent of a hard-coded 7, with the entire function call optimized away:
ldc.i4.7
In other words, the F# compiler is pretty thorough when it comes to optimizing logically identical code blocks.
This is not an exhaustive answer, of course, and there could be some case where they are actually treated differently by the compiler.
Upon covering the predefined datatypes in f# (i.e lists) and how to sum elements of a list or a sequence, I'm trying to learn how I can work with user defined datatypes. Say I create a data type, call it list1:
type list1 =
A
| B of int * list1
Where:
A stands for an empty list
B builds a new list by adding an int in front of another list
so 1,2,3,4, will be represented with the list1 value:
B(1, B(2, B(3, B(4, A))))
From the wikibook I learned that with a list I can sum the elements by doing:
let List.sum [1; 2; 3; 4]
But how do I go about summing the elements of a user defined datatype? Any hints would be greatly appreciated.
Edit: I'm able to take advantage of the match operator:
let rec sumit (l: ilist) : int =
match l with
| (B(x1, A)) -> x1
| (B(x1, B(x2, A))) -> (x1+x2)
sumit (B(3, B(4, A)))
I get:
val it : int = 7
How can I make it so that if I have more than 2 ints it still sums the elemets (i.e. (B(3, B(4, B(5, A)))) gets 12?
One good general approach to questions like this is to write out your algorithm in word form or pseudocode form, then once you've figured out your algorithm, convert it to F#. In this case where you want to sum the lists, that would look like this:
The first step in figuring out an algorithm is to carefully define the specifications of the problem. I want an algorithm to sum my custom list type. What exactly does that mean? Or, to be more specific, what exactly does that mean for the two different kinds of values (A and B) that my custom list type can have? Well, let's look at them one at a time. If a list is of type A, then that represents an empty list, so I need to decide what the sum of an empty list should be. The most sensible value for the sum of an empty list is 0, so the rule is "I the list is of type A, then the sum is 0". Now, if the list is of type B, then what does the sum of that list mean? Well, the sum of a list of type B would be its int value, plus the sum of the sublist.
So now we have a "sum" rule for each of the two types that list1 can have. If A, the sum is 0. If B, the sum is (value + sum of sublist). And that rule translates almost verbatim into F# code!
let rec sum (lst : list1) =
match lst with
| A -> 0
| B (value, sublist) -> value + sum sublist
A couple things I want to note about this code. First, one thing you may or may not have seen before (since you seem to be an F# beginner) is the rec keyword. This is required when you're writing a recursive function: due to internal details in how the F# parser is implemented, if a function is going to call itself, you have to declare that ahead of time when you declare the function's name and parameters. Second, this is not the best way to write a sum function, because it is not actually tail-recursive, which means that it might throw a StackOverflowException if you try to sum a really, really long list. At this point in your learning F# you maybe shouldn't worry about that just yet, but eventually you will learn a useful technique for turning a non-tail-recursive function into a tail-recursive one. It involves adding an extra parameter usually called an "accumulator" (and sometimes spelled acc for short), and a properly tail-recursive version of the above sum function would have looked like this:
let sum (lst : list1) =
let rec tailRecursiveSum (acc : int) (lst : list1) =
match lst with
| A -> acc
| B (value, sublist) -> tailRecursiveSum (acc + value) sublist
tailRecursiveSum 0 lst
If you're already at the point where you can understand this, great! If you're not at that point yet, bookmark this answer and come back to it once you've studied tail recursion, because this technique (turning a non-tail-recursive function into a tail-recursive one with the use of an inner function and an accumulator parameter) is a very valuable one that has all sorts of applications in F# programming.
Besides tail-recursion, generic programming may be a concept of importance for the functional learner. Why go to the trouble of creating a custom data type, if it only can hold integer values?
The sum of all elements of a list can be abstracted as the repeated application of the addition operator to all elements of the list and an accumulator primed with an initial state. This can be generalized as a functional fold:
type 'a list1 = A | B of 'a * 'a list1
let fold folder (state : 'State) list =
let rec loop s = function
| A -> s
| B(x : 'T, xs) -> loop (folder s x) xs
loop state list
// val fold :
// folder:('State -> 'T -> 'State) -> state:'State -> list:'T list1 -> 'State
B(1, B(2, B(3, B(4, A))))
|> fold (+) 0
// val it : int = 10
Making also the sum function generic needs a little black magic called statically resolved type parameters. The signature isn't pretty, it essentially tells you that it expects the (+) operator on a type to successfully compile.
let inline sum xs = fold (+) Unchecked.defaultof<_> xs
// val inline sum :
// xs: ^a list1 -> ^b
// when ( ^b or ^a) : (static member ( + ) : ^b * ^a -> ^b)
B(1, B(2, B(3, B(4, A))))
|> sum
// val it : int = 10
I have found a presentation by Don Syme which shows that Erlang's
fac(0) -> 1
fac(N) -> N * fac(N-1).
is equivalent to F#'s
let rec fac = function
| 0 -> 1
| n -> n * fac (n-1)
But it looks like there is no way to use pattern matching for a different arity without losing type safety. E.g. one could use a list pattern matching, but then a type must be a common base type (such as object):
let concat = function
| [x;y] -> x.ToString() + y.ToString()
| [x] -> x.ToString()
Given that F# functions in modules do not support overloads, it looks like the only way to rewrite Erlang code into F# with static typing is to use static classes with method overloading instead of modules. Is there a better way to rewrite Erlang functions with different arity in F#?
In general, is it correct to say that Erlang's argument matching is closer to .NET's (including C#) method overloading rather than to F#'s pattern matching? Or there is no direct replacement between the two, e.g. there could be a function in Erlang with different arities + a guard:
max(x) -> x.
max(x,y) when x > y -> x.
max(x,y) -> y.
max(comparer, x, y) -> if comparer(x,y) > 0 -> x; true -> y end.
In the last case the arguments are of different types. How would you rewrite it in F#?
You can achieve something close to overloading by rethinking the problem slightly. Instead of thinking about the function as the axis of variability, think of the input as the variable part. If you do that, you'll realise that you can achieve the same with a discriminated union.
Here's a more contrived example than the one in the linked article:
type MyArguments = One of int | Two of int * int
let foo = function
| One x -> string x
| Two (x, y) -> sprintf "%i%i" x y
Usage:
> foo (One 42);;
val it : string = "42"
> foo (Two (13, 37));;
val it : string = "1337"
Obviously, instead of defining such a 'stupid' type as the above MyArguments, you'd define a discriminated union that makes sense in the domain you're modelling.
This code
let rec readNLines n list =
if n = 0 then
list
else
readNLines(n-1,readInt()::list)
ends with
Type mismatch. Expecting a 'a but given a 'a -> 'a
The resulting type would be infinite when unifying ''a' and
''a -> 'a' (using built-in F# compiler)
but runs ok when last line is changed to
readNLines(n-1,(readInt()::list))
or
readNLines(n-1)(readInt()::list)
Question is: Why? :|
Only the last version can work, because readNLines takes two arguments, but
readNLines (n - 1, readInt() :: list)
passes only one argument (which is a tuple consisting of an int and the list).
readNLines (n - 1) (readInt() :: list)
passes them as two separate arguments - the difference here is using the comma (tuple) and space (two arguments).
By the way, that becomes much clearer when you use more whitespace (as I did), because the individual elements are easier to identify.
Take a look at these two functions:
> let f1 a b = a + b
val f1 : a:int -> b:int -> int
> let f2 (a, b) = a + b
val f2 : a:int * b:int -> int
As you can see, they have slightly different types. In function f1 you partially apply the arguments (you'll see the term 'curried function' used here), in function f2 you pass in a tuple of arguments in one "go", or you can think of it as only ever having a single argument (an 'uncurried' function).
What you're doing is defining a function f1 style, but later calling it f2 style, which confuses the compiler.