Feedback on F# idiom and style, what do ;; mean, etc [closed] - f#

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I am mostly looking for feedback on F# idiom and style since I'm just starting out and I'm trying to teach myself. It's never too early to start to adopt best practices.
What are ";;" used for?
Why do functions and expressions in my script.fsx file sometimes seem to need ";;"es (I get syntax errors if the the double semicolons aren't there), and sometimes don't?
In the code below, function test is simply an initial condition guard to test2, which strikes me as inelegant. How could I combine them both into one function? Would there be a reason to try to combine test and test2 into a single function?
main's paramenter argv isn't used here. Can it be deleted?
main is basically a unit test for all the little functions. Is there a more efficient or elegant way to unit test F# code?
Can you put blank lines in a function to improve readability?
open System
(*
2.6 Declare the F# function notDivisible: int * int −> bool where
notDivisible(d, n) is true iff and only if d is not a divisor of n.
For example notDivisible(2, 5) is true, and notDivisible(3, 9) is false.
Hansen, Michael R..
Functional Programming Using F# (pp. 39-40).
Cambridge University Press. Kindle Edition.
*)
let divisible d n = (0 = n % d);;
let notDivisible d n = not (divisible d n);;
(*
2.7
2.7.1 Declare the F# function test: int * int * int -> bool. The value of test(a, b, c),
for a ≤ b, is the truth value of:
notDivisible(a, c) and
notDivisible(a + 1, c) and
.
.
.
notDivisible(b, c)
2.7.2 Declare an F# function prime: int -> bool, where prime(n) = true,
if and only if n is a prime number.
2.7.3 Declare an F# function nextPrime: int -> int,
where nextPrime(n) is the smallest prime number > n.
Hansen, Michael R..
Functional Programming Using F# (p. 40).
Cambridge University Press. Kindle Edition.
*)
let rec test2 a b c =
if (a <= b)
then (notDivisible b c) && (test2 a (b - 1) c)
else true
let test a b c = (a <= b) && (test2 a b c)
let prime n = (n = 2) || ((n > 2) && (test 2 (n - 1) n))
let rec nextPrime n =
if (prime (n + 1))
then (n + 1)
else nextPrime (n + 1)
[<EntryPoint>]
let main argv =
printfn "divisible %d %d: expect %b, get %b" 2 5 false (divisible 2 5)
printfn "divisible %d %d: expect %b, get %b" 3 9 true (divisible 3 9)
printfn "-------------------------------------------------------------------------------"
printfn "not(divisible %d %d): expect %b, get %b" 2 5 true (not(divisible 2 5))
printfn "-------------------------------------------------------------------------------"
printfn "notDivisible %d %d: expect %b, get %b" 2 5 true (notDivisible 2 5)
printfn "notDivisible %d %d: expect %b, get %b" 3 9 false (notDivisible 3 9)
printfn "notDivisible %d %d: expect %b, get %b" 1 1 false (notDivisible 1 1)
printfn "-------------------------------------------------------------------------------"
printfn "test %d %d %d: expected %b, get %b" 1 1 1 false (test 1 1 1) // false
printfn "test %d %d %d: expected %b, get %b" 2 3 4 false (test 2 3 4) // false
printfn "test %d %d %d: expected %b, get %b" 2 1 1 false (test 2 1 1) // false
printfn "test %d %d %d: expected %b, get %b" 2 2 6 false (test 2 2 6) // false
printfn "test %d %d %d: expected %b, get %b" 2 3 6 false (test 2 3 6) // false
printfn "test %d %d %d: expected %b, get %b" 2 1 2 false (test 2 1 2) // false
printfn "test %d %d %d: expected %b, get %b" 2 2 3 true (test 2 2 3) // true
printfn "test %d %d %d: expected %b, get %b" 2 4 5 true (test 2 4 5) // true
printfn "-------------------------------------------------------------------------------"
printfn "prime %d: expect %b, get %b" -1 false (prime -1) // false
printfn "prime %d: expect %b, get %b" 0 false (prime 0) // false
printfn "prime %d: expect %b, get %b" 1 false (prime 1) // false
printfn "prime %d: expect %b, get %b" 2 true (prime 2) // true
printfn "prime %d: expect %b, get %b" 3 true (prime 3) // true
printfn "prime %d: expect %b, get %b" 4 false (prime 4) // false
printfn "prime %d: expect %b, get %b" 5 true (prime 5) // true
printfn "prime %d: expect %b, get %b" 6 false (prime 6) // false
printfn "-------------------------------------------------------------------------------"
printfn "nextPrime %d : expcected, %d, get %d" -1 2 (nextPrime -1) // 2, 2
printfn "nextPrime %d : expcected, %d, get %d" 0 2 (nextPrime 0) // 2, 2
printfn "nextPrime %d : expcected, %d, get %d" 1 2 (nextPrime 1) // 2, 2
printfn "nextPrime %d : expcected, %d, get %d" 2 3 (nextPrime 2) // 3, 3
printfn "nextPrime %d : expcected, %d, get %d" 3 5 (nextPrime 3) // 5, 5
printfn "nextPrime %d : expcected, %d, get %d" 4 5 (nextPrime 4) // 5, 5
printfn "nextPrime %d : expcected, %d, get %d" 5 7 (nextPrime 5) // 7, 7
printfn "nextPrime %d : expcected, %d, get %d" 6 7 (nextPrime 6) // 7, 7
printfn "nextPrime %d : expcected, %d, get %d" 7 11 (nextPrime 7) // 11, 11
//
0 // return an integer exit code

There are two ways of working with F# - compiling an assembly with fsc (.fs files) and writing a script file to be executed with fsi. Bear with me if I'm stating the obvious, it will be relevant later.
Usually when you write a script, you're executing the code as you go, experimenting with it and capturing the results of a REPL session for later. That's where the ;; that are purely an fsi usage artifacts come from (as described in a comment).
One side effect of this REPL based approach is that the shape of things you have in the script may end up reflecting the path of how the implementer got there more than deliberate design, and as scripts are more of a throwaway thing, that is often acceptable. That's how the code might have evolved to have a test2 function with only a single usage - it's an ok idea to roll test and test2 together, and while I might recommend doing that if they're part of some reusable library and test2 has no clear usage scenarios on its own other than being part of test, I don't think it necessarily matters here.
The main function that you have at the end of the file however is an entry point to a console application - so the compiled way of working with F# - and really has no place and special meaning in a script. I believe it was just pasted over and left there for no obvious reason.
[<EntryPoint>]
let main argv =
0
You could just drop that and execute all those lines directly within the script.
You can test F# code using all the standard unit testing frameworks you have for .NET, but that's more of a use case for the compiled assembly path. Scripts are not unit-testable this way, and you'd test them interactively or through inline tests like the ones you have.

Related

F# project compiling error for a function returning a tuple

I created an F# project by visual studio, added function like this:
let fangle a b c =
a+1, b+1, c+1
[<EntryPoint>]
let main argv =
printfn "%i,%i,%i" (fangle 3 4 5) // compile error
There's compiling error at the call of (fangle 3 4 5), it says:
Error 2 The type '(int * int * int)' is not compatible with any of the types
byte,int16,int32,int64,sbyte,uint16,uint32,uint64,nativeint,unativeint,
arising from the use of a printf-style format string
C:\Users\mis\Documents\Visual Studio 2013\Projects\ConsoleApplication1\ConsoleApplication3\Program.fs 20 25 ConsoleApplication3
Why such an error, in my function definition?
it's not your function definition - it's the way you use printfn (the F# compiler is indeed checking if you use the right parameters for the given format-string).
So by doing
printfn "%i,%i,%i" (fangle 3 4 5)
you are telling F# to print three integers (separated by ',') - you can think of it's type to be printf "%i,%i,%i" : int -> int -> int -> unit - but you give it a tuple int*int*int (namely the result of evaluating fangle for a=3, b=4, c=5) so now F# is trying to figure out how to match the first curried type int from printf "%i,%i,%i" with the type int*int*int and I just cannot - therefore the error.
The obvious fix would be:
printfn "%A" (fangle 3 4 5)
where you tell F# to format the resulting tuple:
> printfn "%A" (fangle 3 4 5);;
(4, 5, 6)
val it : unit = ()
or you can first deconstruct the tuple:
> let (x,y,z) = fangle 3 4 5 in printfn "%i,%i,%i" x y z;;
4,5,6
val it : unit = ()
or you can go ballistic/fancy ;)
let uncurry3 f (x,y,z) = f x y z
> uncurry3 (printfn "%i,%i,%i") (fangle 3 4 5);;
4,5,6
val it : unit = ()
Additionally to what Carsten already said in his answer, you can also use the pipe-operator |||> to deconstruct the tuple while passing them as arguments to another function:
let fangle a b c =
a+1, b+1, c+1
[<EntryPoint>]
let main argv =
fangle 3 4 5
|||> printfn "%i,%i,%i"

Are F# Async.Parallel results guaranteed to be in order?

Are the results from F#'s Async.Parallel operation guaranteed to arrive in the order jobs were submitted? My sample code returns the results in order, but I can't find any mention in the MSDN docs, or the F# spec, assuring this must be the case -- that it's not a coincidence.
Here is my sample code:
let r = System.Random()
Async.Parallel [
for i in 0..10 ->
async {
let rand_num = r.Next(10)
do! Async.Sleep(rand_num) (* Simulate jobs taking a variable amount of time *)
printfn "%i %i" i rand_num
return i
}
]
|> Async.RunSynchronously
|> printfn "%A"
And here's the output.
0 0
5 1
4 1
3 3
10 6
9 4
7 5
2 5
1 5
8 7
6 9
[|0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10|]
You can see that, in this run, the async functions complete in indeterminate order, yet the resulting array is sorted. Is this behavior guaranteed?
At the moment, the source of the function is written so that this guarantee is enforced. Looking at control.fs around line #1300 for the definition, we can see the function that puts the results into the output array is
let recordSuccess i res =
results.[i] <- res;
finishTask(Interlocked.Decrement count)
this function is called in this segment
tasks |> Array.iteri (fun i p ->
queueAsync
innerCTS.Token
// on success, record the result
(fun res -> recordSuccess i res)
where tasks has the original tasks in sorted order. This guarantees that the output list is in the same order as the input.
UPDATE
The spec at least seems to imply that the order is fixed - it contains this code:
let rec fib x = if x < 2 then 1 else fib(x-1) + fib(x-2)
let fibs =
Async.Parallel [ for i in 0..40 -> async { return fib(i) } ]
|> Async.RunSynchronously
printfn "The Fibonacci numbers are %A" fibs //I changed this line to be accurate
System.Console.ReadKey(true)
If the spec didn't guarantee the output order, this code would be incorrect.

Match a number if it is multiple of 2

I'm learning f# and currently I'm with the match keyword. I'm modifying the next example, to print into the screen if a numbers is multiple of 2, it's mod is 0.
[<Literal>]
let Three = 3
let filter123 x =
match x with
// The following line contains literal patterns combined with an OR pattern.
| 1 | 2 | Three -> printfn "Found 1, 2, or 3!"
// The following line contains a variable pattern.
| var1 -> printfn "%d" var1
for x in 1..10 do filter123 x
I have modified it and coded an additional match for:
| x % 2 == 0 -> printfn "it's multiple of 2!"
But that doesn't work, it says that "%" it's an undefined symbol... any ideas? Thanks!
This is a classic Tim Toady. The other answers are perfectly correct. I would add a couple of variations:
// Eugene's answer
let filterEven1 x =
match x with
| _ when x % 2 = 0 -> printfn "%d is even!" x
| _ -> printfn "%d is not even" x
// equivalent to above, but with "function" match syntax
let filterEven2 = function
| x when x % 2 = 0 -> printfn "%d is even!" x
| x -> printfn "%d is not even" x
// variation on Gene's answer
let (|Even|Odd|) x =
if x % 2 = 0 then Even(x) else Odd(x)
let filterEven3 = function
| Even(x) -> printfn "%d is even!" x
| Odd(x) -> printfn "%d is not even" x
// probably how I would do it
let filterEven4 x =
match x % 2 with
| 0 -> printfn "%d is even!" x
| _ -> printfn "%d is not even" x
You cannot use an expression as a match case. Another alternative to a guarded pattern would be defining an active pattern:
let(|Even|Odd|) (x:int) =
if x % 2 = 0 then Even else Odd
and then using it as a normal pattern case
.......
| Even -> printfn "it's multiple of 2!"
.......
You need to use guarded pattern rule:
| _ when x % 2 = 0 -> printfn "it's multiple of 2!"

F#: Want to reinitialize enumerator

I have a sequence of prime number divisors that I want to iterate over for each prime candidate. I use GetEnumerator() MoveNext() and Current. I can't reinitialize the enumerator to start from the beginning. I tried Reset(), which compiled, but gives a runtime error of not implemented.
I am using F# 2.0 Interactive build 4.0.40219.1
Any suggestions?
Regards,
Doug
To clarify the problem: For each prime candidate N I want to iterate thru the prime divisors sequence (up to approx sqrt N) and completely factor N or determine if it is prime. Using the GetEnumerator, MoveNext, Current approach works for the first prime candidate, but on the second prime candidate I want to iterate on my divisors sequence from the beginning. It appears that the only way to do this is to create a new iterator (which is awkward for a large number of prime candidates) or create a new prime sequence (which I don't want to do).
The suggestion of using something like "divisors in seqPrimes" appears to exhaust all divisors before stopping, but I want to stop as soon as a prime divisor divides the prime candidate.
If there is an error in my logic in the above statements, please let me know.
I investigated Seq.cache, and this worked for me. The resulting code follows:
// Recursive isprime function (modified from MSDN)
let isPrime n =
let rec check i =
i > n/2 || (n % i <> 0 && check (i + 2))
if n = 2 then true
elif (n%2) = 0 then false
else check 3
let seqPrimes = seq { for n in 2 .. 100000 do if isPrime n then yield n }
// Cache the sequence to avoid recomputing the sequence elements.
let cachedSeq = Seq.cache seqPrimes
// find the divisors of n (or determine prime) using the seqEnum enumerator
let rec testPrime n (seqEnum:System.Collections.Generic.IEnumerator<int>) =
if n = 1 then printfn "completely factored"
else
let nref = ref n
if seqEnum.MoveNext() then
let divisor = seqEnum.Current
//printfn "trial divisor %A" divisor
if divisor*divisor > n then printfn "prime %A" !nref
else
while ((!nref % divisor) = 0) do
printfn "divisor %A" divisor
nref := !nref / divisor
testPrime !nref seqEnum
// test
for x = 1000000 to 1000010 do
printfn "\ndivisors of %d = " x
let seqEnum = cachedSeq.GetEnumerator()
testPrime x seqEnum
seqEnum.Dispose() // not needed
If you mean that the cause of your attempt to reset the Enumerator is the high cost of regenerating your sequence of primes you may consider caching your sequence. This manner of using your sequence would be idiomatic to F#. To show you how to do this I refer you to the following snippet taken from this context:
let rec primes =
Seq.cache <| seq { yield 2; yield! Seq.unfold nextPrime 3 }
and nextPrime n =
if isPrime n then Some(n, n + 2) else nextPrime(n + 2)
and isPrime n =
if n >= 2 then
primes
|> Seq.tryFind (fun x -> n % x = 0 || x * x > n)
|> fun x -> x.Value * x.Value > n
else false
You may play with this snippet to see that the penalty of re-enumeration here gets negligible.
Talking of Reset() method of IEnumerator, I recall that it is not implemented in current F#, i.e. throws System.NotSupportedException. See MSDN reference for justification.
ADDITION:
In order to test it with the test you've suggested below:
for x in [1000000..1000010] do
printfn "\ndivisors of %d" x
primes
|> Seq.takeWhile ((>) (int(sqrt(float x))))
|> Seq.iter (fun n -> if x%n = 0 then printf "%d " n)
On my laptop test execution takes mere 3ms.

F# Seq.initInfinite giving StackOverflowException

I'm learning F#, and I am having trouble understanding why this crashes. It's an attempt to solve Project Euler problem 2.
let rec fibonacci n =
if n = 1 then
1
elif n = 2 then
2
else
fibonacci (n - 1) + fibonacci (n - 2)
let debugfibonacci n =
printfn "CALC: %d" n
fibonacci n
let isEven n =
n % 2 = 0
let isUnderLimit n =
n < 55
let getSequence =
//[1..30]
Seq.initInfinite (fun n -> n)
|> Seq.map debugfibonacci
|> Seq.filter isEven
|> Seq.takeWhile isUnderLimit
Seq.iter (fun x -> printfn "%d" x) getSequence
The final version would call a sum function (and would have a higher limit than 55), but this is learning code.
As is, this gives a StackOverflowException. However, if I comment in the [1..30] and comment out the Seq.initInfinite, I get:
CALC: 1
CALC: 2
2
CALC: 3
CALC: 4
CALC: 5
8
CALC: 6
CALC: 7
CALC: 8
34
CALC: 9
CALC: 10
CALC: 11
It appears to be generating items on demand, as I would expect in LINQ. So why does it blow up when used with initInfinite?
Seq.initInfinite returns a sequence that starts at 0.
Your fibonacci function results in a stack overflow when called with zero, because it never hits the terminating cases.
You can solve this by starting from Seq.initInfinite (fun n -> n + 1)
You're starting with 0 with initInfinite, which then recurses -1, -2, ...
(By the way, if you're using the Visual Studio debugger, this is easy to diagnose, by checking the call stack and locals window.)

Resources