usage of the semicolon in F#, different behaviors - f#

I have the following line:
| ResponseTableTypes.Order ->
orderProcessor.ProcessEvent action message
orderEvent.Trigger()
since I have a lot of entries, for layout reasons, I did:
| ResponseTableTypes.Order -> orderProcessor.ProcessEvent action message; orderEvent.Trigger()
all good, but then I added some return type:
| ResponseTableTypes.Order -> let s = orderProcessor.ProcessEvent action message; orderEvent.Trigger(s)
that will not compile, I get:
The block following this 'let' is unfinished. Every code block is an expression and must have a result. 'let' cannot be the final code element in a block. Consider giving this block an explicit result.
so, if I break down the line again:
| ResponseTableTypes.Order ->
let s = orderProcessor.ProcessEvent action message
orderEvent.Trigger(s)
then it obviously works again
what is happening with the let/semicolon combination?

I will answer your question, but in doing so answer a more important question of how to ask a question.
Starting with | ResponseTableTypes.Order -> let s = orderProcessor.ProcessEvent action message; orderEvent.Trigger(s), let's reduce irrelevancies such as tables, orders, and events:
let result =
let s = expression; action
Now let's ascribe simple values to the names, so that apart from the issue we want to identify, it should compile.
let x =
let y = 0; 0
// FS0588 the block following this let is unfinished.
// FS0020 The result of this expression has type 'int' and is implicitly ignored.
Now that we have a clean question, we can start to answer it, but this is the easy part. let y = 0; 0 is equivalent to let y = (0;0) and so the first 0 is being ignored, and since let y = ... is an incomplete expression which does not return anything, there is nothing to ascribe to x.
There is an antique syntax let y = 0 in 0 which does allow merging multiple lines with lets into one.

Related

F# GreaterThanZero passing int or decimal

I want to create a function that check if the passed value is greater than zero.
The passed value can be an int or a decimal (ideally a "numeric value").
In the immediate I just started with this:
type number =
| I of int
| D of decimal
type Checker () =
member this.Validate value =
match value with
| I x when x > 0 -> "ok"
| D x when x > 0m -> "ok"
| _ -> "error"
let a = 1f
let b = 1m
//let a_IsValid = Checker().Validate(a) // does not compile, expect number (not int)
//let b_IsValid = Checker().Validate(b) // does not compile, expect number (not decimal)
Found not immediate to pass a "number" so tried something different...
I found this article (http://tomasp.net/blog/fsharp-generic-numeric.aspx/) and I thought
"static member constraint" is the perfect solution for me.
A basic example works as expected:
let inline divideByTwo value =
LanguagePrimitives.DivideByInt value 2
divideByTwo 1f |> ignore
divideByTwo 1m |> ignore
but a different scenario found me very surprised:
type Calculator () =
let divideByTwo value =
LanguagePrimitives.DivideByInt value 2
member this.DivideByTwo value =
LanguagePrimitives.DivideByInt value 2
member this.ValidateGeneric value =
match LanguagePrimitives.GenericGreaterThan value 0m with
| true -> "ok"
| _ -> "error"
//let half = Calculator().DivideByTwo(1) // DivideByInt does not support int !!
// cannot use both the following, the first one will "force" the type, and the other will not work
let a_half = Calculator().DivideByTwo(1f) // ok if used before the "decimal" version
let b_half = Calculator().DivideByTwo(1m) // ok only if comment the previous one
It seems not to work when I want to use more than one type for the passing value.
More than that, the function I need (GenericGreaterThan) seems to have another "limitation", explained below.
The example in the article use DivideByInt and, as the name said, it divide the passed value by an int, a well defined type.
LanguagePrimitives.GenericGreaterThan needs 2 parameters, a passed value and a fixed one to compare to. The signature of the function as only one generic type for both, so if you pass a type 'T it expect the second one to be 'T too.
I just wants to compare with zero without passing it, but using "0" forced my value
to be an int and using "0m" force the value to be a decimal.
There is a simple way to have a function that check if a "numeric" value is greater than "zero" ?
Should I use obj and box it .... or use cast ... or stop trying and just use a different function for every type I need ?
[UPDATE]
I tried to use the LanguagePrimitives.GenericZero as suggested but still not able to have a working solution for my particular scenario.
I created a new issue here: F# - Compare LanguagePrimitives.GenericZero with a value passed on the class contructor .
Comparing against zero generically is actually quite simple. The following function should work for any numeric type:
let inline isPositive x =
x > LanguagePrimitives.GenericZero
isPositive 1.0 |> printfn "%A" // true
isPositive 1m |> printfn "%A" // true
Dividing by two generically is also pretty easy. You just have to define your own generic two, since it's not a built-in primitive:
let inline divideByTwo x =
let two =
LanguagePrimitives.GenericOne
+ LanguagePrimitives.GenericOne
x / two
divideByTwo 5.0 |> printfn "%A" // 2.5
divideByTwo 4m |> printfn "%A" // 2
there lots of things here.
your first example didn't work because you needed to wrap your number inside the type number (I assume you realise this? but didnt want it to work like that?)
type Checker () =
member this.Validate value =
match value with
| I x when x > 0 -> "ok"
| D x when x > 0m -> "ok"
| _ -> "error"
let a = I 1
let b = D 1m
let a_IsValid = Checker().Validate(a)
let b_IsValid = Checker().Validate(b)
your second example is that in doesnt support divide by int?
yes what is the value of 1/2? its not an int, so thats correct by design.
the third question seems to be that this code doesnt compile and run?
type Calculator () =
member inline _.DivideByTwo value =
LanguagePrimitives.DivideByInt value 2
let b_half = Calculator().DivideByTwo(1m) // ok for me
let a_half = Calculator().DivideByTwo(1f) // ok for me
but this works for me.
The fourth question appears to be the need to use static constraints to test if something is > 0?
but 0 (as in mathematics) is a different thing in different number systems, its generic too so you need LanguagePrimitives.GenericZero. putting that all together we get
type Calculator () =
member inline _.DivideByTwo value =
LanguagePrimitives.DivideByInt value 2
member inline _.ValidateGeneric value =
match LanguagePrimitives.GenericGreaterThan
value
LanguagePrimitives.GenericZero with
| true -> "ok"
| _ -> "error"
let b_half = Calculator().DivideByTwo(1m)
let a_half = Calculator().DivideByTwo(1f)
let y = Calculator().ValidateGeneric(1m)
let z = Calculator().ValidateGeneric(1f)
as for the divide by 1/2 question, you may need to think what you want it to do? really the input type is defined by what output type you want? decimal? float? etc

F# / Argu - How to display help for two level command tree without throwing exception

I have a two-level F# / Argu command tree. Its abbreviated version looks like that:
[<CliPrefix(CliPrefix.Dash)>]
type RunContGenArgs =
| [<Unique>] [<EqualsAssignment>] [<AltCommandLine("-ql")>] MaxQueueLength of int
with
interface IArgParserTemplate with
member this.Usage =
match this with
| MaxQueueLength _ -> "max queue length."
and
[<CliPrefix(CliPrefix.None)>]
ContGenArguments =
| [<Unique>] [<AltCommandLine("run")>] RunContGen of ParseResults<RunContGenArgs>
with
interface IArgParserTemplate with
member this.Usage =
match this with
| RunContGen _ -> "run Continuous Generation."
which, I then use as follows:
[<EntryPoint>]
let main argv =
let parser = ArgumentParser.Create<ContGenArguments>(programName = "ContGen.exe")
let results = parser.Parse argv
match results.GetAllResults() |> ContGenTask.tryCreate with
| Some task -> task.run()
| None ->
printfn "%s" (parser.PrintUsage())
-1
If I run the command like ContGen.exe run help, then it correctly displays help for the command run. However, it then crashes with ugly exception:
Unhandled Exception: Argu.ArguParseException: USAGE: ContGen.exe runcontgen [help] [-maxqueuelength=<int>]
OPTIONS:
-maxqueuelength, -ql=<int>
max queue length.
help display this list of options.
at Argu.ExceptionExiter.Argu-IExiter-Exit[a](String msg, ErrorCode errorCode) in C:\Users\eirik.tsarpalis\devel\public\Argu\src\Argu\Types.fs:line 62
at Argu.ArgumentParser\`1.Parse(FSharpOption\`1 inputs, FSharpOption\`1 configurationReader, FSharpOption\`1 ignoreMissing, FSharpOption\`1 ignoreUnrecognized, FSharpOption\`1 raiseOnUsage) in C:\Users\eirik.tsarpalis\devel\public\Argu\src\Argu\ArgumentParser.fs:line 180
at Program.main(String[] argv) in C:\GitHub\ClmFSharp\Clm\ContGen\Program.fs:line 8
If I change let results = parser.Parse argv into let results = parser.Parse(argv, raiseOnUsage = false), then it does not crash but does not display any help message. And then since command run can run without any second level argument, the program just keeps going instead of displaying help and quitting.
However, I need ContGen.exe run help just display help message and then quit. How can I achieve that? Thanks.
This is a somewhat peculiar behavior of Argu; you need to provide your own exiter to avoid the exception being thrown there.
Something along these lines:
type NonThrowingExiter() =
interface IExiter with
member __.Name = "Exiter" // I don't know what this is used for; I have never seen it appear anywhere
member __.Exit (msg, code) =
if code = ErrorCode.HelpText then
printfn "%s" msg
exit 0
else
printfn "%s" msg // Maybe have code to color the console output red here
exit 1
To use this, create your `ArgumentParser` like this:
let argumentParser =
Argu.ArgumentParser.Create<ContGenArguments>(helpTextMessage = "Help requested",
errorHandler = NonThrowingExiter())
(You don't actually need to create a class for this, of course; an object expression will do it just as well.)

Debug error : 'let' cannot be the final code element in a block in Fsharp

My code :
let main _ =
let t = (System.Console.In.ReadLine ()) |> int
for i in 1..t do
let n = (System.Console.In.ReadLine ()) |> int
0
And I got errors as following :
The block following this 'let' is unfinished. Every code block is an expression and must have a result. 'let' cannot be the final code element in a block. Consider giving this block an explicit result.
Can you help me ? Thank you very much .
To give some more details on why this is required - in F#, everything (aside from type and module definitions) is expression that has some return value. This even applies to things like printf - they still return value, but it is the unit value, written as (), which represents a dummy value with no information.
The problem is that let <var> = <expr> is not a complete expression, because it does not return anything. The full form is let <var> = <expr1> in <expr2>. This assigns the result of <expr1> to the variable <var> and evaluates <expr2> and returns the result. If you're using a line break, you can omit in, but you still need some body.
In yor example, the best option is to use () as the body, because you're not returning anything useful. You can write this using in or using a line break:
for i in 1..t do
let n = (System.Console.In.ReadLine ()) |> int in ()
for i in 1..t do
let n = (System.Console.In.ReadLine ()) |> int
()
This is not very useful thing to write, because you're not using n anywhere, but that's another question.
Inside your for loop, the last statement is a let. Adding a 0 indented to the same level should fix the problem
Thanks John Palmer . I learned many things . So this's result for the problem :
let t = (System.Console.In.ReadLine ()) |> int
for i in 1..t do
let n = (System.Console.In.ReadLine ()) |> int
printf("%d\n") n
0
0

"let is unfinished. expect an expression" error. I don't see where though

open System
let highLowGame () =
let rng = new Random();
let secretNumber = rng.Next() % 100 + 1
let rec highLowGameStep () =
printfn "Guess a number: "
let guessStr = Console.ReadLine()
let guess = Int32.Parse(guessStr)
match guess with
| _ when guess > secretNumber -> printfn "Too high!" highLowGameStep ()
| _ when guess = secretNumber -> printfn "You got it!" ()
| _ when guess < secretNumber -> printfn "Too low!" highLowGameStep ()
[<EntryPoint>]
let main argv =
highLowGame ()
0 // return an integer exit code
I know there's tons of these questions and I get that a function in F# must have a return variable. Mine is here | _ when guess = secretNumber -> printfn "You got it!" () so I don't understand why it keeps telling me that my block is unfinished
This example is straight out of the F# 3.0 book.
/stdin(14,13): error FS0010: Unexpected identifier in expression. Expected incomplete structured construct at or before this point or other token.
is the full error.
You have to return something at the end of your let statement. Otherwise, your function just defines some values, but the expression isn't complete - you're missing a return value. See this MSDN link for more details.
In this case, you can add highLowGameStep () at the end to call the function and get its return value:
open System
let highLowGame () =
let rng = new Random();
let secretNumber = rng.Next() % 100 + 1
let rec highLowGameStep () =
printfn "Guess a number: "
let guessStr = Console.ReadLine()
let guess = Int32.Parse(guessStr)
match guess with
| _ when guess > secretNumber -> printfn "Too high!" highLowGameStep ()
| _ when guess = secretNumber -> printfn "You got it!" ()
| _ when guess < secretNumber -> printfn "Too low!" highLowGameStep ()
highLowGameStep ()
[<EntryPoint>]
let main argv =
highLowGame ()
0 // return an integer exit code
I was getting the same error as OP for a different reason. The reason was improper indentation. Here is my code:
open System
type Temperature = F of int | C of int
[<EntryPoint>]
let main (argv : string[]) =
let freezing = F 32;
Console.WriteLine("A union: {0}", freezing ); //problematic indentation
printfn "A union: %A" freezing ; //problematic indentation
0
I had copy pasted two lines of code (marked as problematic indentation in comments) from a website and it went haywire. It was giving me three different compile time errors at three different lines of code within main function. When I aligned the indentation of all four statements within main function the issue got resolved:
let main (argv : string[]) =
let freezing = F 32;
Console.WriteLine("A union: {0}", freezing );
printfn "A union: %A" freezing ;
0
I would encourage you to enable View White Space option in Visual Studio IDE while working on F# as mentioned here. Tabs, spaces and code indentation is strongly connected to scoping in F#. Read these posts to gather more understanding around scoping and indentation in F#:
Whitespace and indentation in F#
#indent "off" in F#
Roujo has an excellent answer to your question, I'm throwing up another answer to go more in depth into the fundamentals of what's going on.
The key to remember is that everything in F# must be an expression and an expression is something which has a value. That value could be an integer or a float or a function, but it's gotta have a value. The let isn't, on it's own, an expression; it's a binding of a value to a name so that name can be used in an expression. In your code, you've bound the name highLowGameStep to a function value, but you don't use that name in an expression. The F# compiler is basically left holding the bag, wondering what expression highLowGameStep should be used in.
It helps to use the verbose F# syntax to see what's happening. In verbose F# the code for your function is (note the in keyword after each let binding):
let rng = new Random() in
let secretNumber = rng.Next() % 100 + 1 in
let rec highLowGameStep () =
printfn "Guess a number: "
let guessStr = Console.ReadLine()
let guess = Int32.Parse(guessStr)
match guess with
| _ when guess > secretNumber ->
printfn "Too high!"
highLowGameStep ()
| _ when guess = secretNumber ->
printfn "You got it!"
| _ when guess < secretNumber ->
printfn "Too low!"
highLowGameStep ()
in
In this syntax, it's obvious what's wrong: there's nothing after the last in where F# expects an expression. (Incidentally, the code in the match statements wouldn't have executed because there needed to be a line or ; separating the printfn function call and the call to highLowGameStep.)
Quick summary, the let is binding a name to a value to be used in an expression. In the code example, there was no expression for the bound name to be used in and the compiler failed.

F# pattern matching in function signature

Why doesn't this work?
type RetryBuilder(max) =
member x.Return(a) = a // Enable 'return'
member x.Delay(f) = f // Gets wrapped body and returns it (as it is)
// so that the body is passed to 'Run'
member x.Zero() = failwith "Zero" // Support if .. then
member x.Run(f) = // Gets function created by 'Delay'
let rec loop 0 (Some(ex)) = raise ex
let rec loop n maybeEx = try f() with ex -> loop (n-1) (Some(ex))
loop max None
let retry = RetryBuilder(4)
It says 'incomplete pattern matches on this expression. For example, the value '1' may indicate a case not covered by the pattern'.
But why wouldn't that match the one below? If I remember correctly, Haskell would match that, why doesn't F#?
You're writing F# code in Haskell syntax. The reason why your code compiles is F# compiler thought there are two loop functions where the former is shadowed by the latter. Obviously in the first loop function, pattern matching fails with any integer different from 0 for the first parameter and None for the second parameter.
A declaration close to Haskell syntax could be:
let rec loop = function
| 0, Some ex -> raise ex
| n, maybeEx -> try f() with ex -> loop (n-1, Some ex)
loop(max, None)

Resources