Beginner: Expressions in F# - f#

I want to rewrite this
//finds the max of 3 numbers
let max3 (n1, n2, n3) = let mx1 = if (n1 > n2) then n1 else n2 in if (mx1 > n3) then mx1 else n3;
without using "in"
I came up with this
let max3 (n1, n2, n3) =
let mx1 =
if (n1 > n2)
then n1
else n2
let mx2=
if (mx1 > n3)
then mx1
else n3;;
Says let is unfinished and expects an expression.
Not sure why. mx2 is suppost to get the higher value of the set and move it over to the next function that is in its scope.
I also want to be able to do this such that I dont use any let expressions. Please any help in understanding this language would be really kind
EDIT: Can anyone answer my question below? Also is such a problem possible with out using any let expressions in F#?

let max3 (n1, n2, n3) = max n1 (max n2 n3)
// val max3 : n1:'a * n2:'a * n3:'a -> 'a when 'a : comparison
max3 (13,4,7)
The max is predefined for 2 parameters and can be composed as above.
If you declare no types it will be generic with a constraint that the type 'a needs to have a comparison function.
In F# the function parameters are normally not tuples like (n1, n2, n3),
instead it can be defined as
let max3 n1 n2 n3 = max n1 (max n2 n3)
// val max3 : n1:'a -> n2:'a -> n3:'a -> 'a when 'a : comparison
max3 13 4 7

Says let is unfinished and expects an expression.
Not sure why. mx2 is suppost to get the higher value of the set and move it over to the next function that is in its scope.
Regarding this specific question. Every function must return some value. The last "expression" in the function is considered a return value of that function.
let foo a b c =
let x = a + b
y + c
Here, y + c is the last expression, and it's value is the "return value" of function foo.
However, declaring and binding some value (let x = a + b) is a statement, not an expression, and it doesn't have any value, so the following code won't compile.
let foo a b c =
let result = a + b + c
If you wanted to return the value of mx2 in your original code, you'd have to convert the binding statement (let mx2 = ...) into an expression:
let max3 (n1, n2, n3) =
let mx1 = ...
if (mx1 > n3)
then mx1
else n3

Related

Issue With Factorial Function

I have been trying to write a program which prints out a factorial without actually using recursion.
Here is the code
let factorial x =
let mutable n = x
while n > 0 do
let result = n*(n-1)
n <- (n-1)
result
The issue is that when I try to run the code it tells me that the expected result is a unit, whereas the input is clearly an integer, which obviously results in an error. However, I have checked all my variables and the compiler interprets them as integers, so what is the issue
There are several issues with your code here, you must keep in mind indentation in f# is very important, for you want to do your code should be:
let factorial x =
let mutable n = x
let mutable result = 1
while n > 0 do
result <- n * (n-1)
n <- (n - 1)
result
You were declaring the result variable inside the while scope and returning it outside it. Your code however is incorrect, I took the liberty of modify it, here what I did:
let factorial x =
let mutable n = x
let mutable result = 1
while n >= 1 do
result <- result * n
n <- (n - 1)
result

Desugared form of "let in"

What do the let (x = 0) in x * x translate to? A function (fun x -> x * x) 0) ? - This would make sense, as let bindings are expressions - and expressions must return values (just like functions).
Example:
let result1 =
(fun n1 -> (fun n2 ->
(fun n3 -> n1 + n2 + n3 ) 3) 2) 1
let result2 =
let n1 = 1 in
let n2 = 2 in
let n3 = 3 in
n1 + n2 + n3
let result3 =
let n1 = 1
let n2 = 2
let n3 = 3
n1 + n2 + n3
Am I right to assume that result3 is a sugared form of result2, and result2 a sugared form of result1?
Short: Do let in bindings translate to functions?
You can almost see let x = e1 in e2 as a syntactic sugar for (fun x -> e2) e1.
At the basic level, the two expressions mean the same thing - the compiler will probably compile them differently (depending on optimization levels and how it inlines things), but you could often use the second notation instead of the first one.
The one case where they differ is that ML-languages (including F#) only generalize function types written explicitly using the let keyword. This means that if you use fun, the language won't treat it as a generic function. If you want a generic function, you have to use let (and this is not just a compiler artifact, this is actually part of the language).
For example, the following uses let and it works:
let id = (fun x -> x) in ignore(id 1); ignore(id "A")
But the following does not work, because id is not a generic function:
(fun id -> ignore(id 1); ignore(id "A")) (fun x -> x)
The plain old let is just the lightweight syntax form of the verbose let … in.
From MSDN: Verbose Syntax (F#):
nested let bindings:
Lightweight syntax:
let f x =
let a = 1
let b = 2
x + a + b
Verbose syntax:
let f x =
let a = 1 in
let b = 2 in
x + a + b
The let bindings within these function don't translate to functions themselves, however. Both of these translate to identical CIL code:
f:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.1
IL_0003: add
IL_0004: ldc.i4.2
IL_0005: add
IL_0006: ret
Note that the only function here is the outer function f. The variables a and b are evaluated as constants within the scope of f.
let x = <val> in <expr> is functionally equivalent to (fun x -> <expr>) <val>.
<expr> is an expression
<val> is a value
The in keyword is optional.

F# assuming int when actually dealing with int64

Going through Project Euler trying to learn F#, I stumbled upon what appears to be a type inference problem while writing a solution for problem 3.
Here's what I wrote:
let rec findLargestPrimeFactor p n =
if n = 1 then p
else
if n % p = 0 then findLargestPrimeFactor p (n/p)
else findLargestPrimeFactor (p+1) n
let result = findLargestPrimeFactor 2 600851475143L
However, the compiler gives me the following error:
error FS0001: This expression was expected to have type int but here has type int64
Since I expect the types used in findLargestPrimeFactor to be inferred from usage, I'm quite surprised to find out the compiler seems to assume that parameter n be an int since in the only call to the function is done with an int64.
Could someone explain to me:
why the compiler appears to be confused about types
how to work around this limitation
The types in findLargestPrimeFactor are inferred from usage. The F# compiler performs type inference in a top-to-bottom manner, so the types of p and n (the parameters of findLargestPrimeFactor) are inferred from their usage in the function. By the time the compiler sees the let result = ..., the parameter types have already been inferred as int.
The easiest solution is to use the L suffix on all of your constant values, so the types will be inferred as int64:
let rec findLargestPrimeFactor p n =
if n = 1L then p
else
if n % p = 0L then findLargestPrimeFactor p (n/p)
else findLargestPrimeFactor (p + 1L) n
let result = findLargestPrimeFactor 2L 600851475143L
If you want a fancier solution, you can use the generic one and zero constants from the LanguagePrimitives module. This allows findLargestPrimeFactor to be generic(-ish) so it can be reused more easily with different numeric types:
open LanguagePrimitives
let rec findLargestPrimeFactor p n =
if n = GenericOne then p
else
if n % p = GenericZero then findLargestPrimeFactor p (n/p)
else findLargestPrimeFactor (p + GenericOne) n
(* You can use one of these, but not both at the same time --
now the types of the _arguments_ are used to infer the types
of 'p' and 'n'. *)
//let result = findLargestPrimeFactor 2L 600851475143L
let result = findLargestPrimeFactor 2 Int32.MaxValue
Per #kvb's suggestion, here's how you can write this function generically:
open LanguagePrimitives
let inline findLargestPrimeFactor p n =
let rec findLargestPrimeFactor p n =
if n = GenericOne then p
else
if n % p = GenericZero then findLargestPrimeFactor p (n/p)
else findLargestPrimeFactor (p + GenericOne) n
findLargestPrimeFactor p n
(* Now you can call the function with different argument types
as long as the generic constraints are satisfied. *)
let result = findLargestPrimeFactor 2L 600851475143L
let result' = findLargestPrimeFactor 2 Int32.MaxValue

Is there a way to do a multiple value comparison inline?

I feel silly for even asking this because it seems so trivial but my brain is failing me. If I had the following:
let a, b, c = 1, 1, 1
Is there an eligant way to determine if a, b, and c all hold the same value. Something like:
let result = (a = b = c)
This fails because the expression a = b returns true and the next expression results in true = c and complains that it was expecting int, not bool. The only thing I can think of is:
a = b && a = c && b = c
which won't work when I want to add more variables.
Really what I'm trying to do is this:
let same (x: string * string * string) =
match x with
| (a, a, a) -> true
| _ -> false
I was hoping that I could match all the elements into one element and if they were different it would move on, but it says on the second element in the match that it has already been bound.
To check if every value in a list is the same:
let rec same = function
| x::y::_ when x <> y -> false
| _::xs -> same xs
| [] -> true
Usage
let a, b, c = 1, 1, 1
same [a; b; c] //true
let same (a, b, c) = a = b && b = c
I would try to use the forall function in order to determine if all of the numbers are same.
let list = [a; b; c;];;
List.forall (fun n -> n = a) list;;
val it : bool = true
This solution produces exactly the required syntax. Surprisingly to myself, is fairly fast. Also, is seems to be a good example of using monads, also known as Computation Expressions.
// Generic
let inline mOp1<'a> op sample x = op sample x, sample
let inline mOp2<'a> op1 op2 (b, sample) x = op1 b (op2 sample x), sample
// Implementation for (=) and (&&)
let (==) = mOp1 (=)
let (&=) = mOp2 (&&) (=)
// Use
let ret1 = a == b &= c &= d &= e |> fst
How it works
The approach is a very simplified State monad. The monadic type is a tuple of (bool, 'T). The first component is the boolean value of ongoing calculation, and the second is the sample value to compare with.
(==) would initialize the monad, similar to Delay operator.
(&=) is used for all subsequent comparisons. It is similar to Bind operator.
We don't need Return because fst would serve pretty fine.
mOp1 and mOp2 are abstractions over the logical operations. These allow defining your own operators. Here are examples of or-equal and and-greater-than:
let (|=) = mOp2 (||) (=)
let (.>) = mOp1 (>)
let (&>) = mOp2 (&&) (>)
// Use
let ret2 = a == b |= c |= d |= e |> fst // if any of b,c,d,e equals to a
let ret3 = 5 .> 3 &> 4 |> fst // true: 5>3 && 5>4
let ret4 = 5 .> 3 &> 8 &> 4 |> fst // false
Performance
I really enjoyed the beautiful solution by #ildjarn, but constructing List is quite slow, so my primary goal was performance.
Running a chain of 8 comparisons, 10 million times:
04972ms a=b && a=с && ...
23138ms List-based
12367ms monadic

F# Checked Arithmetics Scope

F# allows to use checked arithmetics by opening Checked module, which redefines standard operators to be checked operators, for example:
open Checked
let x = 1 + System.Int32.MaxValue // overflow
will result arithmetic overflow exception.
But what if I want to use checked arithmetics in some small scope, like C# allows with keyword checked:
int x = 1 + int.MaxValue; // ok
int y = checked { 1 + int.MaxValue }; // overflow
How can I control the scope of operators redefinition by opening Checked module or make it smaller as possible?
You can always define a separate operator, or use shadowing, or use parens to create an inner scope for temporary shadowing:
let f() =
// define a separate operator
let (+.) x y = Checked.(+) x y
try
let x = 1 +. System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
// shadow (+)
let (+) x y = Checked.(+) x y
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
// shadow it back again
let (+) x y = Operators.(+) x y
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
// use parens to create a scope
(
// shadow inside
let (+) x y = Checked.(+) x y
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
)
// shadowing scope expires
try
let x = 1 + System.Int32.MaxValue
printfn "ran ok"
with e ->
printfn "exception"
f()
// output:
// exception
// ran ok
// exception
// ran ok
// exception
// ran ok
Finally, see also the --checked+ compiler option:
http://msdn.microsoft.com/en-us/library/dd233171(VS.100).aspx
Here is a complicated (but maybe interesting) alternative. If you're writing something serious then you should probably use one of the Brians suggestions, but just out of curiosity, I was wondering if it was possible to write F# computation expression to do this. You can declare a type that represents int which should be used only with checked operations:
type CheckedInt = Ch of int with
static member (+) (Ch a, Ch b) = Checked.(+) a b
static member (*) (Ch a, Ch b) = Checked.(*) a b
static member (+) (Ch a, b) = Checked.(+) a b
static member (*) (Ch a, b) = Checked.(*) a b
Then you can define a computation expression builder (this isn't really a monad at all, because the types of operations are completely non-standard):
type CheckedBuilder() =
member x.Bind(v, f) = f (Ch v)
member x.Return(Ch v) = v
let checked = new CheckedBuilder()
When you call 'bind' it will automatically wrap the given integer value into an integer that should be used with checked operations, so the rest of the code will use checked + and * operators declared as members. You end up with something like this:
checked { let! a = 10000
let! b = a * 10000
let! c = b * 21
let! d = c + 47483648 // !
return d }
This throws an exception because it overflows on the marked line. If you change the number, it will return an int value (because the Return member unwraps the numeric value from the Checked type). This is a bit crazy technique :-) but I thought it may be interesting!
(Note checked is a keyword reserved for future use, so you may prefer choosing another name)

Resources