F# ((*)2) and ((<<<)1) act differently - f#

I have these two pieces of code:
[| 0 .. N-1 |] |> Array.map((<<<)1)
[| 0 .. N-1 |] |> Array.map((*)2)
I thought they do absolutely the same things but they don't.
In first case I get 1, 2, 4 and in second - 0, 2, 4. I don't understand why there is 1 in the first case? If I write let a = 0 <<< 1, I get 0. Is this a bug?
Thanks!

The arguments are not in the order you think, they are the other way around.
Compare it with:
let a = 1 <<< 0 // this is equivalent to ((<<<)1) 0
The first argument after the parenthesized operator is the left argument, not the right.

Related

Reversing Bits in F#

I need help reversing bits in F# as done in this question Reverse bits in number. I'm new to F# and was wondering how we can do this?
let bitreverse x =
let mutable b = 0
while x do
b >>>= 1
b|= x & 1
x >>>= 1
b
I'm not even sure the syntax is correct here. I am very knew to this language.
The direct translation into F# looks like this:
let bitreverse x =
let mutable x = x
let mutable b = 0
while x <> 0 do
b <- b <<< 1
b <- b ||| (x &&& 1)
x <- x >>> 1
b
This is highly imperative with mutable values and this isn't usually how we'd tend to go about writing code in F#. Notice that re-assignment of a mutable variable is a little different to what you might be used to in an imperative language, you have to use <- which is called the destructive update operator.
Thankfully, it's pretty straightforward to translate this into a recursive function that uses immutable values which should be a little more idiomatic
let bitreverse2 x =
let rec bitRerverseHelper b x =
match x with
|0 -> b // if 0, the recursion stops here and we return the result: b
|_ -> bitRerverseHelper ((b <<< 1) ||| (x &&& 1)) (x >>> 1) // otherwise recurse
bitRerverseHelper 0 x
F# doesn't support compound assignment, so you can't do something like b |= x & 1, you need to expand it to b <- b ||| (x &&& 1).
The argument x isn't mutable, so you need to create a local binding and mutate that. It looks weird, but you can just write let mutable x = x as the first line of your function to shadow the existing binding with a mutable one.
x is an int, not a bool, so you can't use it as the condition for your while loop. Use x <> 0 instead.
Indentation matters in F#, so make sure that while and your final b both line up with the first let.
Fixing those issues will make your code work, but idiomatic F# would probably forgo the while loop and mutation and use a recursive inner function with an accumulator instead.

Adding a list of numbers based on an operator

I am really new to F# and am struggling to adapt to the whole functional programming mindset. Basically I am trying to figure out how to iterate through a list of numbers and add them up while the sum is less than a certain number (200 for instance).
At the moment I have something along the lines of the following:
let nums = [20 .. 50]
let mutable total = 0
let addUp (num, (total : byref<int>)) =
if (num + total < 200) then
total <- total + num
for num in nums do
addUp (num, &total)
This does get the job done, but I feel like there must be a more appropriate way to do this while still remaining within the style of functional programming, and without out having to rely on a mutable. I still feel like I'm approaching things from an imperative mindset.
I was thinking I could somehow use List.fold to do this but after some experimentation I was unable to figure out how to utilize it in conjunction with the whole while < 200 thing. Any help would be hugely appreciated and I apologize in advance if this is a commonly asked and answered question (I couldn't find anything through my own search).
For educational purposes, the answer above is fine as it lets you see what exactly happens within the fold or reduce.
For a real project, it is better to use existing library functions. You can even separate summation and bound checking. Consider this:
let addUp threshold xs =
xs
|> Seq.scan (+) 0 // line 1
|> Seq.takeWhile (fun x -> x < threshold) // line 2
|> Seq.last // line 3
// Usage:
let nums = Seq.initInfinite ( (+) 20) // line 4
nums
|> addUp 200
|> printfn "%d" // prints "188"
A bit of explanation:
line 1 is a contraction of Seq.scan (fun state x -> state + x) 0 so it actually returns a sequence of intermediate sums (20, 41, 63, ...);
in line 2, we take only the elements that match or filtering predicate;
in line 3, we simply take the last element (that matched the filtering above);
in line 4, again, it's a contraction of Seq.initInfinite (fun x -> 20+x). I took my liberty to make your data an infinite sequence (20, 21, 22, ...), but it still works.
Note, the code looks like three calls, but the sequence is evaluated only once.
Note, in line 2, don't try contraction like above. The reason is that (<) threshold evaluates to fun x -> threshold < x which is wrong. If you. however, use (>) threshold, it reads counter-intuitive and confusing.
Note, there's no error checking in the function. Calling it with an empty source sequence will crash at Seq.last.
First, let's try to avoid mutable variable and one way to do it is to create a recursive function to iterate through the list with the latest total.
let rec addUp total nums =
match nums with
| [] -> total
| num::tl ->
let newTotal = num + total
if newTotal < 200 then
addUp newTotal tl
else
total
addUp 0 nums
We create a recursive function addUp which accepts total and the list of numbers. The function extracts the first number of the list and adds it to the total if the new total is less than 200. Since we might still have more numbers on the list, we call addUp again with the new total and the rest of the numbers. Otherwise, we stop and return the new total.
We can also use List.fold which makes the code cleaner, but the whole list will be iterated. Here is the code:
List.fold (fun total num ->
let newTotal = num + total
if newTotal < 200 then
newTotal
else
total
) 0 nums
Since the output is the same type as the member of the input, we can use List.reduce and get rid of initial state (0).
List.reduce (fun total num ->
let newTotal = num + total
if newTotal < 200 then
newTotal
else
total
) nums
Hope this helps.

F# For loop negative count down - Type int does not support the operator ..-

Am trying to count down from 6 to 1 in a non-recursive factorial function and getting a compiler error:
let fact x =
let mutable product = 1
for i in x..-1..1 do
product <- product * i
product
// Error on the 6 - type 'int' does not support the operator '..-'
let answer = fact 6
printfn "%i" answer
I got this idea from near the bottom here
Have changed the function to just count up and it works, but I'm interested to know why this failed. Is there a better way to count down?
Using VS2012 update 3
Have changed the function to just count up and it works, but I'm interested to know why this failed.
Your example fails because .. and - are two different operators, the compiler needs separation between those. Instead of wrapping -1 by parentheses, you could add spaces:
let fact x =
let mutable product = 1
for i in x .. -1 .. 1 do
product <- product * i
product
Is there a better way to count down?
The less well-known for .. downto .. do construct is more appropriate to use here.
let fact x =
let mutable product = 1
for i = x downto 1 do
product <- product * i
product
This works:
let fact x =
let mutable product = 1
for i in x..(-1)..1 do
product <- product * i
product
As does this (as used in the link in the question):
let fact x =
let mutable product = 1
for i in x .. -1 .. 1 do
product <- product * i
product
PS: also note that there are more functional ways to compute a factorial (bad to use mutable variables); the most obvious using recursion:
let rec fact x =
if x > 2
then x * (fact (x - 1))
else x
or a one-liner using lists:
let fact x = [2..x] |> List.reduce (*)
Try to use brackets:
...
for i in x..(-1)..1 do
...

Type inference in pattern match over list

I'm stuck with trying to create a function that will do the following:
let p = [1, 2, 4, 2, 1]
let v = 8
then I want to go over the elements in a until I find the index i of the one where all elements up to and including i are greater or equal than v. So in this case it should return 4, because 1+2+4 < 8 and 1+2+4+2 > 8. So there 4th element, value of 2 puts the total over 8.
(some background: I want to do monte carlo, where I have a list of probabilies that add up to 1. Then I pass a random number between 0 and 1 to have it pick one of the possible future states. Simple example here with ints)
What I have so far is this:
let p = [1, 2, 4, 2, 1]
let pick (v:int) (l:int list) =
let rec sub (i:int) (acc:int) (l2:int list) =
match l2 with
| h::t -> if acc+h >= v then i else sub(i+1, acc+h, t)
| _ -> failwith "total list didn't amount to " + v
sub 0 0 l
pick 8 p
But it gives the following error on the bit sub(i+1, acc+h, t):
error FS0001: This expression was expected to have type
int
but here has type
int -> int list -> int
But I'm not passing the function sub itself, I'm calling it complete with arguments and brackets and all, so why doesn't it return int, the result of the function?
How do I make it return the result of the function?
Thanks in advance,
Gert-Jan
you give the 3-tuple (i+1,acc+h,t) where curried function is supposted to be:
| h::t -> if acc+h >= v then i else sub (i+1) (acc+h) t
Try this.
First, p will be understood as [(1, 2, 4, 2, 1);] which is an (int*int*int*int*int) list with only one element. p as an int list should be [1; 2; 4; 2; 1].
Second, sub(i+1, acc+h, t) in line 6 should be called in the curried form, not in the tuple form. The correction is sub (i+1) (acc+h) t.

Why doesn't my code compile?

let sub (m:double[],n:double[]) : double[]=
[| for i = 0 to Array.length m -1 do m.[i]-n.[i] |]
Error 1 This value is not a function and cannot be applied E:\MyDocuments\Visual Studio 2010\Projects\curve intersection\newton\Module1.fs 27 21 newton
But, this is ok:
let a = [| "a"; "b"; "c"; "d"; "e"; "f" |]
for i = 0 to Array.length a - 1 do
System.Console.WriteLine(a.[i])
Spaces around a minus sign matter:
f -1 // means f(-1)
calls the function f with an argument of -1 (unary minus). Whereas
n - 1
and
n-1
are subtraction.
The compiler error reflects that
Array.length m -1
parses as
(Array.length m)(-1)
as though it is expecting the first expression to return a function, which will then be applied to the value -1. Since length actually returns an int, you get the error message that says that an integer is not a function and cannot be applied to the argument -1.
This compiles:
let sub (m:double[], n:double[]) : double[] =
[| for i = 0 to Array.length m - 1 do yield m.[i] - n.[i] |]
The format of your list/array comprehension is wrong.
you either use -> as a short cut:
let a = [1;2;3]
[| for i in a -> i |]
or formally write yield:
[| for i in a do yield i |]

Resources