F#, This value is not a function and the + operator - f#

This code:
let extractTime line =
let result = Regex.Match(line, "(\d\d):(\d\d):(\d\d)")
let captureGroups = List.tail [for g in result.Groups -> g.Value]
match captureGroups with
| hrs::mins::secs::[] -> ((int hrs)*3600) + ((int mins)*60) +(int secs)
| _ -> 0
Gives the error: "This value is not a function and cannot be applied" on this part of the code
((int mins)*60)
I bashed my head on it for a while, then added a space here
+ (int secs)
Taking out the spaces altogether also makes the error go away. e.g.
((int hrs)*3600)+((int mins)*60)+(int secs)
I don't understand why that space makes a difference. Can someone please explain it to me.

It's because +(int secs) is interpreted as a value (+ being a unary operator), in which case ((int mins)*60) would need to be a function, for it to make sense. When there is no space, the following + can't possibly be interpreted as anything else than the binary operator. You can compare it with the following simple lines:
> 1 + 2;;
val it : int = 3
> 1 +2;;
1 +2;;
^
stdin(2,1): error FS0003: This value is not a function and cannot be applied
> 1 2;;
1 2;;
^
stdin(3,1): error FS0003: This value is not a function and cannot be applied
> 12;;
val it : int = 12

Related

F# calling function that returns record in for loop only executes once

I mainly work in C# and am new to F#/function languages and I'm having a problem with a pretty simple program.
I have a function that creates a record with two integer fields. The fields are chosen System.Random.NextDouble inside a match to align with certain probabilities. I then have a for loop that should run the createCustomer function four times.
The problem I'm having is that the Customer is the same for all 10 iterations of the for loop and the printfn inside of getIATime only seems to execute once.
Program.fs
open Simulation
[<EntryPoint>]
let main argv =
printfn "%A" argv
printfn "Test"
for i in 1 .. 10 do
let mutable customer = createCustomer
printfn "i: %d\tIA: %d\tService: %d" i customer.interArrivalTime customer.serviceTime
ignore (System.Console.ReadLine()) //Wait for keypress # the end
0 // return an integer exit code
Simulation.fs
module Simulation
type Customer = {
interArrivalTime: int
serviceTime: int
}
let createCustomer =
let getRand =
let random = new System.Random()
fun () -> random.NextDouble()
let getIATime rand =
printf "Random was: %f\n" rand
match rand with
| rand when rand <= 0.09 -> 0
| rand when rand <= 0.26 -> 1
| rand when rand <= 0.53 -> 2
| rand when rand <= 0.73 -> 3
| rand when rand <= 0.88 -> 4
| rand when rand <= 1.0 -> 5
let getServiceTime rand =
match rand with
| rand when rand <= 0.2 -> 1
| rand when rand <= 0.6 -> 2
| rand when rand <= 0.88 -> 3
| rand when rand <= 1.0 -> 4
{interArrivalTime = getIATime (getRand()); serviceTime = getServiceTime (getRand())}
Your getCustomer is not a function, but a value. Its body is executed only once during program initialization, and the result is stored in a field, which can then be accessed. When you think that you "call" the function, you actually merely reference the value. No calling is going on, because there is nothing to call.
To make getCustomer a function, give it a parameter. This is how functions differ from values in F#: if you have a parameter, you're a function; if not - you're a value. Since there is no actual data that you'd want to pass to the function, you can give it a "dummy" ("placeholder") parameter of type unit. This type has exactly one value, and that value is written as ():
let createCustomer () =
let getRand =
let random = new System.Random()
fun () -> random.NextDouble()
...
Then call it like this:
for i in 1 .. 10 do
let mutable customer = createCustomer()
printfn "i: %d\tIA: %d\tService: %d" i customer.interArrivalTime customer.serviceTime

Overflow of an int in f#

I am working on some homework and we are supposed to be making a combination function in F#. I have got the factorial function down, but it seems to overflow once I get a big number to use factorial on. (Let's say 20) I understand I can use an int64 or a float, but that would change all the inputs on the code. What data type should I use?
let rec Fact (a:int)=
if (a = 0) then 1 else a*Fact(a-1);;
let combo (n:int) (k:int)=
if (n = 0) then 0 else (Fact n)/((Fact k)*(Fact (n-k)));;
On the code right now, when I do combo 20 5;; it gives me 2147. Which is clearly the wrong answer. I looked at the factorial function and when I put 20 in there it gave me a big negative number. Any help would be much appreciated. Thanks in advance.
First of all, if you want to avoid surprises, you can open the Checked module at the top of your file. This will redefine the numerical operators so that they perform overflow checks - and you'll get an exception rather than unexpected number:
open Microsoft.FSharp.Core.Operators.Checked
As Fyodor points out in the comment, you cannot fit factorial of 20 in int and you need int64. However, your combo function then performs division which will make the result of combo 20 5 small enough to fit into int.
One option is to change Fact to use int64, but keep combo as a function that takes and returns integers - you'll need to convert them to int64 before calling Fact and then back to int after performing the division:
let rec Fact (a:int64) =
if (a = 0L) then 1L else a * Fact(a-1L)
let combo (n:int) (k:int) =
if (n = 0) then 0 else int (Fact (int64 n) / (Fact (int64 k) * Fact (int64 (n-k))))
Now you can call combo 20 5 and you'll get 15504 as the result.
EDIT: As noted by #pswg in the other answer, int64 is also quite limited and so you'll need BigInteger for larger factorials. However, the same method should work for you with BigInteger. You can keep the combo function as a function that returns int by converting back from BigInteger to int.
You simply won't be able to do that with an 32-bit integer (int). A 64-bit integer will get you up to 20!, but will fail at 21!. The numbers just get too big, too quickly. To go any further than that you'll need to use System.Numerics.BigInteger (abbreviated bigint in F#).
The parameter can probably stay as an int to be reasonable, but you need to return a bigint:
let rec Fact (n : int) =
if n = 0 then bigint.One else (bigint n) * Fact (n - 1)
Or to be a little more idiomatic:
let rec Fact = function | 0 -> bigint.One | n -> (bigint n) * Fact (n - 1)
And now, in your Combo function, you'll need to use these bigint's internally for all math (thankfully the integer division is all you need in this case).
let Combo (n : int) (k : int) =
if n = 0 then bigint.Zero else (Fact n) / ((Fact k) * (Fact (n - k)))
If you really wanted to make Combo return an int, you can do that conversion here:
let Combo (n : int) (k : int) =
if n = 0 then 0 else (Fact n) / ((Fact k) * (Fact (n - k))) |> int
Examples:
Combo 20 5 // --> 15504
Combo 99 5 // --> 71523144 (would break if you used int64)
Edit: By rethinking your implementation of Combo you can get some big performance improvements out of this. See this question on Math.SE for the basis of this implementation:
let ComboFast (n : int) (k : int) =
let rec Combo_r (n : int) = function
| 0 -> bigint.One
| k -> (bigint n) * (Combo_r (n - 1) (k - 1)) / (bigint k)
Combo_r n (if (2 * k) > n then n - k else k)
A quick benchmark showed this to be significantly faster than the Fact-based version above:
Function Avg. Time (ms)
Combo 99 5 30.12570
ComboFast 99 5 0.72364

How to convert a list of binary to char?

I would like to convert a list of zeros and ones to a char.
example :
bitToChar([1,0,0,0,1,0,1]) = $Q
Thanks.
Another way to do it is to use a bit string comprehension:
X = [1,0,0,0,1,0,1],
<<C:7>> = << <<Bit:1>> || Bit <- lists:reverse(X) >>,
$Q == C.
That is, pick one element at a time from the list, and use each element as a bit in the binary being built, and finally extract a seven-bit number into the variable C.
You can add $0 to each of them (to make it a string with $0s and $1s), reverse the list, and use list_to_integer/2 with base 2:
1> list_to_integer(lists:reverse([N + $0 || N <- [1,0,0,0,1,0,1]]), 2) == $Q.
true
You can also use lists:foldl. The code is slightly longer but it doesn't use list_to_binary:
1> element(2, lists:foldl(fun(Digit, {Mul, Acc}) -> {Mul * 2, Acc + Digit * Mul} end, {1, 0}, Xs)) == $Q. true
This is basically equivalent to doing: 1 * 1 + 0 * 2 + 0 * 4 + 0 * 8 + 1 * 16 + 0 * 32 + 1 * 64.
$Q = lists:foldr(fun(X,Acc) -> X + (Acc bsl 1) end, 0,[1,0,0,0,1,0,1]).
Since $Q is integer value all you have to do is use in BitToChar conversion from binary based number to decimal based number.
Simplest conversion is:
to_decimal(X) ->
to_decimal(lists:reverse(X), 1, 0).
% you can validate that if H = 1 then add, if other not but I omitted this validation
to_decimal([H | T], Times, Acc) ->
to_decimal(T, 2 * Times, H * Times + Acc);
to_decimal([], _Times, Acc) -> Acc.
And then it will return integer.
In your case:
> $Q = 81.
81
> $Q == 81.
true

F#: Not understanding match .. with

I'm messing around with F# and Fable, and trying to test my understanding. To do so, I tried creating a function to calculate e given a certain number of iterations. What I've come up with is
let eCalc n =
let rec internalECalc ifact sum count =
match count = n with
| true -> sum
| _ -> internalECalc (ifact / (float count)) (sum + ifact) (count+1)
internalECalc 1.0 0.0 1
Which works fine, returning 2.7182818284590455 when called with
eCalc 20
However, if I try using, what I think is, the more correct form
let eCalc n =
let rec internalECalc ifact sum count =
match count with
| n -> sum
| _ -> internalECalc (ifact / (float count)) (sum + ifact) (count+1)
internalECalc 1.0 0.0 1
I get a warning "[WARNING] This rule will never be matched (L5,10-L5,11)", and returned value of 0. (and the same thing happens if I swap 'n' and 'count' in the match statement). Is there a reason I can't use 'n' in the match statement? Is there a way around this so I can use 'n'?
Thanks
When you use a name in a match statement, you're not checking it against the value assigned to that variable the way you think you are. You are instead assigning that name. I.e.,
match someInt with
| n -> printfn "%d" n
will print the value of someInt. It's the equivalent of let n = someInt; printfn "%d" n.
What you wanted to do was use a when clause; inside a when clause, you're not pattern-matching, but doing a "standard" if check. So what you wanted was:
let eCalc n =
let rec internalECalc ifact sum count =
match count with
| cnt when cnt = n -> sum
| _ -> internalECalc (ifact / (float count)) (sum + ifact) (count+1)
internalECalc 1.0 0.0 1
Does that make sense, or do you need me to go into more detail?
P.S. In a case like this one where your match function looks like "x when (boolean condition involving x) -> case 1 | _ -> case 2", it's quite a bit more readable to use a simple if expression:
let eCalc n =
let rec internalECalc ifact sum count =
if count = n then
sum
else
internalECalc (ifact / (float count)) (sum + ifact) (count+1)
internalECalc 1.0 0.0 1

Syntax Error in Erlang

I'm new to the language and trying to figure out the formatting for a simple function that returns the roots of a quadratic equation.
discriminant(A,B,C) ->
B * B - 4 * A * C.
get_roots(A,B,C) when A == 0 -> error;
get_roots(A,B,C) when discriminant(A,B,C) == 0 -> [(-B/(2*A))];
get_roots(A,B,C) when discriminant(A,B,C) > 0 ->
D = discriminant(A,B,C);
[((-1 * B + math:sqrt(D)) / 2 * A), ((-1 * B - math:sqrt(D)) / 2 * A)];
get_roots(A,B,C) when discriminant(A,B,C) < 0 -> [].
What is the syntactical mistake that I've made? The error that I get when I enter "c(ps04)" in the shell, where ps04.erl is the file in which I wrote my function, is:
ps04.erl:15: syntax error before: '['
ps04.erl:23: Warning: variable 'Head' is unused %for a different function defined later
error
You cannot use a function in guard, so get_roots(A,B,C) when discriminant(A,B,C) == 0 is forbidden.
AS mention by #Amon there is a semicolon that should be replaced by a comma. I would write the function like this:
get_roots(0,0,_) -> [];
get_roots(0,B,C) -> [-C/B];
get_roots(A,B,C) -> get_roots(A,B,C,A*A-4*B*C).
get_roots(A,B,C,0) -> [-B/(2*A)];
get_roots(A,B,C,D) when D > 0 ->
RD = math:sqrt(D),
[(-B+RD)/(2*A),(-B-RD)/(2*A)];
get_roots(_,_,_,_) -> [].
You should replace the semicolon in D = discriminant(A,B,C); with a comma:
D = discriminant(A,B,C),.
By having a semicolon, you're ending this specific get_roots/3 function clause, which is not what you want (you have an additional clause below it obviously).
On a side note, I've noticed from two of your other questions that you have never accepted an answer. If someone has answered your question and it is a valid solution, click the checkmark next to that answer.

Resources