The block after 'let' is unfinished - try/with - f#

Follow Code F#:
try
let result = 100/0
with
| :? Exception as ex -> printfn ex.Message
I get an error:
The block after 'let' is unfinished. Each block of code is an
expression and must have a result. 'let' can not be the final code
element in a block. Consider giving this block an explicit result.
What am I doing wrong ?

The issue is that let by itself is not an expression:
In F# everything is an expression of a certain type. But let alone is not an expression, is a binding and it has to be continued with some expression that, presumably, uses the value bound to the id result.
Since you are merely testing the try/catch functionality. I assume you are not really interested in producing any values, that is why I added the expression: () after the let.
try
let result = 100/0
()
with
ex -> printfn "%s" ex.Message
The try/with expression requires that both sides return the same type of value, just like if/then/else does. Since in the with side printfn returns unit, I made the try side also return a unit value which is (). Think of it as the equivalent to void in C#.

I can recommend different approach. This won't leave the result variable undefined.
let result =
try
Some(100/0)
with
| :? Exception as ex -> printfn "%s" ex.Message; None

Related

F# kprintf: missing warning about about redundant arguments

Is there a way to do string formatting for Exceptions with kprintf (or similar) and still get warnings about redundant arguments? So far I have:
type MyException (s:string) =
inherit System.Exception(s)
static member Raise msg =
Printf.kprintf (fun s -> raise (MyException(s))) msg
do
MyException.Raise "boom %d" 9 1 // Gives NO warning about redundant arguments
failwithf "boom %d" 9 1 // Gives warning about redundant arguments
I know I could use the new $ formatting but would like to stay compatible with older versions of F#.
The problem does not come from kprintf, but from raise, which allows the return type of the function to be any type, including a curried function. The function failwithf has this warning as a special case.
If you return, let’s say, a string or a unit, you would actually get an error. The downside is that now you cannot raise in every position anymore, as then the return argument is not generic anymore.
You could fix that by forcing a type argument, but that would make it less than ideal for the caller.
For instance, this works, but if you change the return type of f to be a string, it fails:
open System
type MyException (s:string) =
inherit System.Exception(s)
static member Raise msg =
Printf.kprintf (fun s -> raise (MyException s) |> ignore) msg
module Test =
let f() : unit = // string won’t work
MyException.Raise "boom %d" 9 10 // error, as expected
Edit: workaround
Here's some kind of a workaround. You can use generic type constraints to limit the type, and use the fact that an F# function type is not comparable or equatable, does not have a proper value null.
Most types you'll use are equatable, because of F#'s powerful structural equality support. Other options for a type constraint are struct (only structs), null (this excludes record and DU types) or a certain inheritance constraint if that serves your use case.
Example:
type MyException (s:string) =
inherit System.Exception(s)
static member Raise<'T when 'T : equality> msg =
let raiser s =
raise (MyException s)
Unchecked.defaultof<'T> // fool the compiler
Printf.kprintf raiser msg
module Test =
let f() = MyException.Raise "boom %d" 9
let g() = MyException.Raise "boom %d" 9 10 // error
Downside, apart from the type restriction, is that the error you get will be a type error, not a warning as you requested.
The check for this warning in the compiler specifically looks for a number of known F# library functions. You can see the checks in the compiler source code and here (the functions are raise, failwith, failwithf, nullArg, invalidOp and invalidArg).
The reason for this is that, there is, in principle, nothing wrong with a generic function that returns 'T and is used so that 'T is inferred to be a function. For example, it is perfectly fine to do:
let id f = f
id sin 3.14
Here, we define a function id with one argument, but if I give it a function as an argument, it also becomes valid to call it with an extra argument as id sin 3.14.
The special functions are special in that they look like they return a value of a generic type, but they never actually return, because they raise an execption. The compiler cannot, in general, know whether that is the case for any custom function or method you yourself write - and so it only checks this for known special functions. (It would have to do more sophisticated analysis, possibly marking the return type of these functions as the bottom type, but that is beyond what F# does...).

F#: How exactly is ToString supposed to be used?

I am learning F# but I just don't understand how I am supposed to use ToString. Below are a few attempts. The syntax errors are saying it is expecting type string but that it is actually type uint -> string. So it doens't actually appear to be invoking a function? Could this be explained? This seems like such a simple thing to do but I can't figure it out.
open System
open System.IO
open FSharp.Data
[<EntryPoint>]
let main (args: string[]) =
let htmlPage = HtmlDocument.Load("https://scrapethissite.com/")
printfn "%s" htmlPage.ToString // This causes a syntax error
htmlPage.ToString
|> (fun x -> printfn "%s" x) // This also causes a syntax error
0
.ToString is a method, not a value. In F# every method and every function has a parameter. In fact, that's how functions differ from values (and methods from properties): by having a parameter.
Unlike in C#, F# methods and functions cannot be parameterless. If there is nothing meaningful that you'd want to pass to the method, that method would still have one parameter of type unit. See how this is visible in the error message? unit -> string is the type.
To call such method, you have to pass it the parameter. The sole value of type unit is denoted (). So to call the method you should do:
htmlPage.ToString ()
|> printfn "%s"
Your first example is a bit more complicated. The following would not work:
printfn "%s" htmlPage.ToString ()
Why? Because according to F# syntax this looks like calling printfn and passing it three parameters: first "%s", then htmlPage.ToString, and finally (). To get the correct order of calls you have to use parentheses:
printfn "%s" (htmlPage.ToString ())
And finally, general piece of advice: when possible try to avoid methods and classes in F# code. Most things can be done with functions. In this particular case, the ToString methods can be replaced with the equivalent function string:
printfn "%s" (string htmlPage)

Empty with/finally block in try statement

I want to try something:
try
0/0
and I don't care if it fails, raising an Exception. But leaving a with or finally block empty makes the file unparsable.
This works, but it's not fun to write.
finally
null |> ignore
How to leave the with/finally blocks (as) empty (as possible)?
Every expression must have a result, and try ... with is no exception. The try part is evaluated and a result is obtained. But if the try part fails, the result of the with part is substituted instead.
If your try part is 0/0, then the result type of it is int. Therefore, in order for the types to match, the result of your with part should also be int. Think about what the result of the whole expression should be when the try part fails, and stick it in there:
let foo =
try 0/0
with _ -> 42
Since you're saying that null |> ignore works, I must conclude that your try part is not in fact 0/0. The ignore function returns () (a value of type unit), so if that works for you in the with part, then your try part must be also returning unit. If that is the case, you can use () as the with part instead of null |> ignore.
let foo =
try printfn "Let's pretend that printfn may fail"
with _ -> ()
For reference, this is (roughly) how ignore is defined:
let ignore x = ()

Break a statement (expression) into multiple lines: how to indent

I found it's very hard to search for the simple indentation guide in F#.
Basically, I am wondering what's the rule for multiple-line statement indentation.
In C#, there is no problem because whitespace doesn't count.
Although I can write F# code according to my intuition and it works, I really want to know what's the rule for breaking one statement into multiple lines.
I write as
printfn "%d"
1
It works as expected
And if I write them in the same column, something goes wrong.
>
printfn "%A%A"
1
[];;
> //nothing is returned... and no error in this case
I want to confirm the basic rule for doing this. It's a little annoying when you can't be sure what you are doing.
Thanks in advance
I just tried another case
List.iter
(printfn "%d")
[1..10];;
And it prints out 1 to 10.
Why it's not
List.iter
((printfn "%d")
[1..10]);;
As Yin points out, the rule is that arguments of a function should be indented further than the call to the function. To add more details, your first snippet is interpreted like this:
printfn "%A%A";
1;
[];
Each of these is a valid expression that returns something (function, number, empty list) and then ignores the result and continues. Because they are written in the top-level scope, F# Interactive doesn't emit a warning that you're ignoring some values. If they were in a do block or let declaration:
do
printfn "%A%A"
1
[]
The F# compiler would emit a warning when sequencing expressions (using ;) that do not return unit:
stdin(5,3): warning FS0193: This expression is a function value, i.e. is missing arguments. Its type is 'a -> 'b -> unit.
stdin(6,3): warning FS0020: This expression should have type 'unit', but has typ
e 'int'. Use 'ignore' to discard the result of the expression, or 'let' to bind
the result to a name.
stdin(5,3): warning FS0020: This expression should have type 'unit', but has typ
e ''a list'. Use 'ignore' to discard the result of the expression, or 'let' to b
ind the result to a name.
In your second example, you should indent:
>
printfn "%A%A"
1
[];;
Otherwise the three expressions are three sequential expressions, not a single expression.
You can refer F# Language Specification for firm rules, e.g. Chapter 15 in the specification.

F# - "Not a valid property expression"

I'm having this method which takes a Expr as parameter:
member x.HasSeq (expr:Expr<'a -> 'b seq>) =
let casted = <# fun z -> (%expr) z :?> ICollection<'b> #>
ManyNavPropertyInfo(cfg.HasMany <| toLinq casted)
What I want is to cast the 'b seq to an ICollection<'b>, which seems to work as it should, however when it reaches the line where it's going to convert the Expr to LINQ (need to do this since cfg.HasMany excepts a System.Expression<Func<'a,ICollection<'b>>>) it simply throws an exception saying:
InvalidOperationException:
The expression 'z =>
UnboxGeneric(ToFSharpFunc(z =>
z.Books).Invoke(z))' is not a valid
property expression. The expression
should represent a property: C#: 't =>
t.MyProperty' VB.Net: 'Function(t)
t.MyProperty'.
The function I use for converting Expr to LINQ:
let toLinq (exp : Expr<'a -> 'b>) =
let linq = exp.ToLinqExpression()
let call = linq :?> MethodCallExpression
let lambda = call.Arguments.[0] :?> LambdaExpression
Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters)
I've used the toLinq function before without problems - I think it's because I cast b seq to ICollection<'b> which leaves UnboxGeneric in the Expr and when passing the Expr to toLinq it simply dosent know what to do with the UnboxGeneric - but of course thats just a theory, and I dont know what to do at all, in order to resolve it.
Your reasoning is correct - the problem is that the HasMany method recognizes only specific C# expression trees and the expression tree that your F# code generates is different.
My guess is that EF only handles a case when the expression tree is a plain access to a property of the right type - in the C# syntax something like: x => x.Foo (without any casting etc.). I think that the best option would be to modify your code to also expect a function 'a -> ICollection<'b>.
If you have some way for building a correct expression tree - e.g. if user specifies x => x.Foo, you want to return x => x.FooInternal, then you can use patterns & functions for working with F# quotations to rebuild the expression tree:
let hasSeq (e:Expr<'a -> seq<'b>>) =
match e with
| Patterns.Lambda(v, Patterns.PropertyGet(Some instance, propInfo, [])) ->
printfn "Get property %s of %A" propInfo.Name instance
// TODO: Use 'Expr.Lambda' & 'Expr.PropGet' to construct
// an expression tree in the expected format
| _ -> failwith "Not a lambda!"
... but keep in mind that the result needs to match the structure expected by HasMany. I guess that replacing the actual property specified by the user with some other property (e.g. some internal version that has the right type) is pretty much the only thing you can do.

Resources