I'm reading through an F# tutorial, and ran into an example of syntax that I don't understand. The link to the page I'm reading is at the bottom. Here's the example from that page:
let rec quicksort2 = function
| [] -> []
| first::rest ->
let smaller,larger = List.partition ((>=) first) rest
List.concat [quicksort2 smaller; [first]; quicksort2 larger]
// test code
printfn "%A" (quicksort2 [1;5;23;18;9;1;3])
The part I don't understand is this: ((>=) first). What exactly is this? For contrast, this is an example from the MSDN documentation for List.partition:
let list1 = [ 1 .. 10 ]
let listEven, listOdd = List.partition (fun elem -> elem % 2 = 0) list1
printfn "Evens: %A\nOdds: %A" listEven listOdd
The first parameter (is this the right terminology?) to List.partition is obviously an anonymous function. I rewrote the line in question as this:
let smaller,larger = List.partition (fun e -> first >= e) rest
and it works the same as the example above. I just don't understand how this construct accomplishes the same thing: ((>=) first)
http://fsharpforfunandprofit.com/posts/fvsc-quicksort/
That's roughly the same thing as infix notation vs prefix notation
Operator are functions too and follow the same rule (ie. they can be partially applied)
So here (>=) first is the operator >= with first already applied as "first" operand, and gives back a function waiting for the second operand of the operator as you noticed when rewriting that line.
This construct combines two features: operator call with prefix notation and partial function application.
First, let's look at calling operators with prefix notation.
let x = a + b
The above code calls operator + with two arguments, a and b. Since this is a functional language, everything is a function, including operators, including operator +. It's just that operators have this funny call syntax, where you put the function between the arguments instead of in front of them. But you can still treat the operator just as any other normal function. To do that, you need to enclose it on parentheses:
let x = (+) a b // same thing as a + b.
And when I say "as any other function", I totally mean it:
let f = (+)
let x = f a b // still same thing.
Next, let's look at partial function application. Consider this function:
let f x y = x + y
We can call it and get a number in return:
let a = f 5 6 // a = 11
But we can also "almost" call it by supplying only one of two arguments:
let a = f 5 // a is a function
let b = a 6 // b = 11
The result of such "almost call" (technically called "partial application") is another function that still expects the remaining arguments.
And now, let's combine the two:
let a = (+) 5 // a is a function
let b = a 6 // b = 11
In general, one can write the following equivalency:
(+) x === fun y -> x + y
Or, similarly, for your specific case:
(>=) first === fun y -> first >= y
Related
I found the following piece of code in the fantomas library for F#. I am having a hard time understanding this as an F# noob. From what I understand, it's a custom operator that takes 3 arguments, but why would an operator need 3 arguments? And what exactly is happening here?
/// Function composition operator
let internal (+>) (ctx: Context -> Context) (f: _ -> Context) x =
let y = ctx x
match y.WriterModel.Mode with
| ShortExpression infos when
infos
|> Seq.exists (fun x -> x.ConfirmedMultiline)
->
y
| _ -> f y
Here's an example of how fantomas uses this operator in ther CodePrinter module.
let short =
genExpr astContext e1
+> sepSpace
+> genInfixOperator "=" operatorExpr
+> sepSpace
+> genExpr astContext e2
Operators behave a lot like function names:
let (++) a b c d =
a + b + c + d
(++) 1 2 3 4
One difference is that operators can be used infix. An operator with more than 2 arguments allows infix only for the first 2 arguments:
// the following is equal:
let f = (++) 1 2 // like a function name
let f = 1 ++ 2 // with infix
f 50 60
I did not find how fantomas uses the operator you mention, would be curious, in particular since fantomas is a high profile f# project.
It might be instructive to compare this to the regular function composition operator, >>. The definition for this is:
let (>>) (f : a' -> b') (g : b' -> c') (x : a') =
g ( f x )
Esentially, it applies f to x, and then applies g to the result.
If we have the following functions:
let plusOne i = i + 1
let timesTwo j = j * 2
And apply it the following way:
let plusOneTimesTwo = plusOne >> timesTwo
What we're really doing is something like this:
let plusOneTimesTwo = (>>) plusOne timesTwo
When you don't supply all of the necessary arguments to a function (in this case, x), what you get is a function that takes the remaining arguments and then returns what the original function would return (this is partial application.) In this case, plusOneTimesTwo's function signature is now x : int -> int.
The example you've listed is essentially the same thing, but it's performing additional logic to determine whether it wants to apply the second function to the result y or to return it as-is.
in F# if I take a function that takes two arguments, for example, mod (%):
13 % 10
// val it : int = 3
which is the same as
(%) 13 10
// val it : int = 3
is there any way to write it in the pipe notation, currying the 13?
Obviously, the “two-argument function” is actually a one-argument function that returns an intermediate function. So can pipe
10 |> (%) 13
// val it : int = 3
However, I need the other way around, i.e. pipe the first argument 13, having the second argument 10 partially applied, but not the first one.
Is there anything in the language that helps to do that, without creating extra lambdas every time, i.e. to avoid the following?
13 |> (fun x -> x % 10)
There is no built-in, standard way to do this. Moreover, due to how function application works, it's impossible to do so: as soon as you write (%) 13, you've already applied the first argument, because function application has the highest and non-configurable precedence in F#.
You can, if course, make yourself a special function to produce a "weird" function application - one that would apply the second argument and leave a hole for the first:
let ap f x = fun y -> f y x
And then:
let x = 13 |> ap (%) 10
> x : int = 3
Incidentally, the function ap is a semi-standard occurrence in ML languages, and is usually called flip, because what it does is "flipping" the order of the arguments:
let flip f x y = f y x
Or, you can even make it into an operator:
let (-*-) = flip
And then:
let x = 13 |> (%) -*- 10
> x : int = 3
However, this sort of trickery gets unreadable very quickly. In practice, it is far more preferable to just declare a function that does what you need:
let mod10 x = x % 10
And then:
let x = 13 |> mod10
Or, if you really need it to be very general:
let mod' x y = y % x
And then:
let x = 13 |> mod' 10
You can write a combinator that will do this for any function of two arguments:
let inline flip f y x = f x y
This can be used as:
13 |> flip (%) 10
F# already contains an operator that will do what you want, namely <|:
10 |> (%) <| 13;;
val it : int = 10
This is equivalent to
(10 |> (%)) 13;;
val it : int = 10
K, you are looking for a flip
let flip f a b = f b a
I've been trying to get my head round various bits of F# (I'm coming from more of a C# background), and parsers interest me, so I jumped at this blog post about F# parser combinators:
http://santialbo.com/blog/2013/03/24/introduction-to-parser-combinators
One of the samples here was this:
/// If the stream starts with c, returns Success, otherwise returns Failure
let CharParser (c: char) : Parser<char> =
let p stream =
match stream with
| x::xs when x = c -> Success(x, xs)
| _ -> Failure
in p //what does this mean?
However, one of the things that confused me about this code was the in p statement. I looked up the in keyword in the MSDN docs:
http://msdn.microsoft.com/en-us/library/dd233249.aspx
I also spotted this earlier question:
Meaning of keyword "in" in F#
Neither of those seemed to be the same usage. The only thing that seems to fit is that this is a pipelining construct.
The let x = ... in expr allows you to declare a binding for some variable x which can then be used in expr.
In this case p is a function which takes an argument stream and then returns either Success or Failure depending on the result of the match, and this function is returned by the CharParser function.
The F# light syntax automatically nests let .. in bindings, so for example
let x = 1
let y = x + 2
y * z
is the same as
let x = 1 in
let y = x + 2 in
y * z
Therefore, the in is not needed here and the function could have been written simply as
let CharParser (c: char) : Parser<char> =
let p stream =
match stream with
| x::xs when x = c -> Success(x, xs)
| _ -> Failure
p
The answer from Lee explains the problem. In F#, the in keyword is heritage from earlier functional languages that inspired F# and required it - namely from ML and OCaml.
It might be worth adding that there is just one situation in F# where you still need in - that is, when you want to write let followed by an expression on a single line. For example:
let a = 10
if (let x = a * a in x = 100) then printfn "Ok"
This is a bit funky coding style and I would not normally use it, but you do need in if you want to write it like this. You can always split that to multiple lines though:
let a = 10
if ( let x = a * a
x = 100 ) then printfn "Ok"
Consider the following code:
let mutable a = 0.
let b = ref 0.
a <- // works
printfn "%A" a
4. + 8.
b := // does not work
printfn "%A" a
4. + 8.
b := ( // works
printfn "%A" a
4. + 8. )
Why does the ref assignment operator (:=) have a different behaviour than the mutable assignment operator (<-)?
I can only give a partial answer.
:= is defined in terms of <- in FSharp.Core\prim-types.fs:
let (:=) x y = x.contents <- y
In your example
b := // does not work
printfn "%A" a
4. + 8.
printfn "%A" a seems to be interpreted as y, which cannot be assigned to the int ref cell (wrong type). By grouping the whole expression with ( ... ), y now also contains 4. + 8.. Maybe the two operators behave differently, because <- seems to be an intrinsic operator (i.e. part of the language, not the library).
Building on the other answers...
More elaborate expressions are allowed within assignments, so long as the final expression is one of several allowed forms. See section 6.4.9 of the spec. This allows complex assignments such as:
let x =
let rec gcd a = function
| 0 -> a
| b -> gcd b (a % b)
gcd 10 25
The compiler moves gcd to a private member, but nesting it within the assignment allows for tighter scoping. Function arguments, on the other hand, are more restricted. They don't create a new scope (that I'm aware of) and you can't define functions, for example, as part of the expression.
:= is a function (try (:=);; in FSI) which has a type : 'a ref -> 'a -> unit
So
b := // does not work
printfn "%A" a
4. + 8.
is being parsed as because of the infix call parsing rule:
(:=) b (printfn "%A" a)
4. + 8.
Which is invalid as par the (:=) function type.
Other example:
let c = 10 +
11
12
c would be 12 here
Looks like a discrepancy in the indentation-sensitive parser rather than anything specifically to do with those operators.
Consider the following code:
let fn () =
let b =
8. // any expression
-b
let fn2 () =
let b =
8. // any expression
- b
"fn" compiles whereas "fn2" does not (notice the space in front of "b"). The error message is:
Block following this 'let' is unfinished. Expect an expression.
Why is that?
F# allows for various kinds of "undentation", where you are allowed to use a lesser indent, but still stay within the same expression.
One such legal "undent" is for operators. You can write
foo
|> bar
|> baz
or
foo
|> bar
|> baz
or even
foo
|> bar
|> baz
and the infix operators continue the same expression on a subsequent line. The rule is that you are allowed to "undent" the "length of the infix operator plus one space", the intent being that this allows you to align the values you're using. A common case is like a table of numbers, like
let x =
42
+ 21
+ 62
where the line below 42 is allowed to start at a two-space lesser indent so that the next number is aligned under the prior one.
So anyway, that rule is kicking in here, and without a space, the 'binary minus' takes precedence over the 'unary minus' and then the infix undent rule kicks in.
fn2 is parsed as:
let fn2 () =
let b = 8. - b
The let block is unfinished, it needs a return value, eg.
let fn2 () =
let b = 8. - b
b
I suggest you to use spaces around binary operators, and no spaces after unary operators.
In the same way, there's a difference between x - 2 (substraction) and x -2 (call function x with argument -2).
It's your indenting of the 8.
When I enter this code:
let fn () =
let b =
8.
-b
let fn2 () =
let b =
8.
- b
It compiles correctly. What's happening is that in the first example fn2 is equivalent to:
let b = 8 - b
and the compiler needs something else to finish the let block (I always read let block as "let foo = bar in expr"). So you're missing the expr part. In the fn, you're getting "let b = 8. in -b".