Understanding type mismatch error? - f#

Why does this statement give me a type mismatch error,
let x = List.rev [] in (3::x, true::x);;
while this statement does not?
let x = [] in (3::x, true::x);;
I'm assuming it is because x is given a function call in the first statement, while it is only give an empty list in the second statement. But, I am not sure exactly why the second works and the first does not? Any help will be much appreciated. Thanks!

Try the following:
let x = [] ;;
Result: val x : 'a list. F# knows that x is a list of as-yet unknown type. If it had any contents, its type would be known. This works perfectly well.
But the following will not work:
let x = List.rev [] ;;
Result:
error FS0030: Value restriction. The value 'x' has been inferred to have generic type
val x : '_a list
Either define 'x' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.
The "value restriction" error in F# can be hard to understand — why is [] allowed when List.rev [] is not? — but this article goes into some details. Essentially, F# can always feel safe making functions generic, but it can only feel safe making values generic if the following two conditions apply:
The expression on the right-hand side of the let is a pure value, e.g. it has no side-effects,
and
The expression on the right-hand side of the let is immutable.
When the expression is [], then F# knows that it's a pure, immutable value, so it can make it generic ('a list). But when the expression is someFunction [], the F# compiler doesn't know what someFunction is going to do. Even though in this case, we know that List.rev is part of the standard library and matches those two scenarios, the F# compiler can't know that. In a completely pure language like Haskell, you can know from a function's type signature that it's pure, but F# is a more pragmatic language. So F# takes the guaranteed-safe approach and does not make the result of List.rev [] generic.
Therefore, when you write let x = [] in (3::x, true::x), the [] value is a generic empty list, so it can become either an int list or a bool list as needed. But when you write let x = List.rev [] in (3::x, true::x), F# cannot make List.rev [] generic. It can say "This is a list of a type I don't yet know", and wait for the type to become clear. Then the first expression of a specific type that uses this list, in this case 3::x, will "lock" the type of that list. I.e., F# cannot consider this list to be generic, so now it has figured out that this empty list is an empty list of ints. And then when you try to append a bool to an empty int list, that's an error.
If you flipped the tuple around so that it was true::x, 3::x then the type error would "flip" as well: it would expect a bool list and find an int list.
So the short version of this answer is: you're hitting the F# value restriction, even though that's not immediately obvious since the error you got didn't mention value restriction at all.
See Understanding F# Value Restriction Errors for a good discussion of the value restriction, including the most common place where you'd normally see it (partially-applied functions).

Related

Understanding F# value restriction

I'm learning F#. I'm here because I had something hard to understand about value restriction.
Here are the examples from the book I'm studying with.
let mapFirst = List.map fst
Since I had learned FP with haskell, I was pretty sure that this code would be well compiled, but it was not the case. It resulted error FS0030 (Sorry that I can't copy-paste fsi error message, since it was written in korean). Instead, I had to provide an explicit argument like:
let mapFirst inp = List.map fst inp // or inp |> List.map fst
But why? I thought that with the above example, compiler can surely infer the type of given value:
val mapFirst : ('a * 'b) list -> 'a list
If I remind correctly, I called this thing in haskell eta-conversion, and above two examples are entirely identical. (Maybe not entirely, though). Why should I privide parameters explicitly to the function can be curried without any loss of information?
I've understood that something like
let empties = Array.create 100 []
will not compile and why, but I don't think It has something to do with my question.
※ I took a look on this question, but it did not help.
This has to do with mutability.
Consider this snippet:
type T<'a> = { mutable x : 'a option }
let t = { x = None }
The type of t is T<'a> - that is, t is generic, it has a generic parameter 'a, meaning t.x can be of any type - whatever the consumer chooses.
Then, suppose in one part of the program you do:
t.x <- Some 42
Perfectly legitimate: when accessing t you choose 'a = int and then t.x : int option, so you can push Some 42 into it.
Then, suppose in another part of your program you do:
t.x <- Some "foo"
Oh noes, what happens now? Is t.x : int option or is it string option? If the compiler faithfully compiled your code, it would result in data corruption. So the compiler refuses, just in case.
Since in general the compiler can't really check if there is something mutable deep inside your type, it takes the safe route and rejects values (meaning "not functions") that are inferred to be generic.
Note that this applies to syntactic values, not logical ones. Even if your value is really a function, but isn't syntactically defined as such (i.e. lacks parameters), the value restriction still applies. As an illustration, consider this:
type T<'a> = { mutable x : 'a option }
let f t x =
t.x <- Some x
let g = f { x = None }
Here, even though g is really a function, the restriction works in exactly the same as with my first example above: every call to g tries to operate on the same generic value T<'a>
In some simpler cases the compiler can take a shortcut though. Thus, for example this line alone doesn't compile:
let f = List.map id
But these two lines do:
let f = List.map id
let x = f [1;2;3]
This is because the second line allows the compiler to infer that f : list int -> list int, so the generic parameter disappears, and everybody is happy.
In practice it turns out that this shortcut covers the vast majority of cases. The only time you really bump against the value restriction is when you try to export such generic value from the module.
In Haskell this whole situation doesn't happen, because Haskell doesn't admit mutation. Simple as that.
But then again, even though Haskell doesn't admit mutation, it kinda sorta does - via unsafePerformIO. And guess what - in that scenario you do risk bumping into the same problem. It's even mentioned in the documentation.
Except GHC doesn't refuse to compile it - after all, if you're using unsafePerformIO, you must know what you're doing. Right? :-)

This expression was expected to have type 'unit' but here has type 'string'

I was attempting to convert this to F# but I can't figure out what I'm doing wrong as the error message (in title) is too broad of an error to search for, so I found no resolutions.
Here is the code:
let getIP : string =
let host = Dns.GetHostEntry(Dns.GetHostName())
for ip in host.AddressList do
if ip.AddressFamily = AddressFamily.InterNetwork then
ip.ToString() // big fat red underline here
"?"
A for loop in F# is for running imperative-style code, where the code inside the for loop does not produce a result but instead runs some kind of side-effect. Therefore, the expression block in an F# for loop is expected to produce the type unit, which is what side-effect functions should return. (E.g., printfn "Something" returns the unit type). Also, there's no way to exit a for loop early in F#; this is by design, and is another reason why a for loop isn't the best approach to do what you're trying to do.
What you're trying to do is go through a list one item at a time, find the first item that matches some condition, and return that item (and, if the item is not found, return some default value). F# has a specialized function for that: Seq.find (or List.find if host.AddressList is an F# list, or Array.find if host.AddressList is an array. Those three functions take different input types but all work the same way conceptually, so from now on I'll focus on Seq.find, which takes any IEnumerable as input so is most likely to be what you need here).
If you look at the Seq.find function's type signature in the F# docs, you'll see that it is:
('T -> bool) -> seq<'T> -> 'T
This means that the function takes two parameters, a 'T -> bool and seq<'T> and returns a 'T. The 'T syntax means "this is a generic type called T": in F#, the apostrophe means that what follows is the name of a generic type. The type 'T -> bool means a function that takes a 'T and returns a Boolean; i.e., a predicate that says "Yes, this matches what I'm looking for" or "No, keep looking". The second argument to Seq.find is a seq<'T>; seq is F#'s shorter name for an IEnumerable, so you can read this as IEnumerable<'T>. And the result is an item of type 'T.
Just from that function signature and name alone, you can guess what this does: it goes through the sequence of items and calls the predicate for each one; the first item for which the predicate returns true will be returned as the result of Seq.find.
But wait! What if the item you're looking for isn't in the sequence at all? Then Seq.find will throw an exception, which may not be the behavior you're looking for. Which is why the Seq.tryFind function exists: its function signature looks just like Seq.find, except for the return value: it returns 'T option rather than 'T. That means that you'll either get a result like Some "ip address" or None. In your case, you intend to return "?" if the item isn't found. So you want to convert a value that's either Some "ip address or None to either "ip address" (without the Some) or "?". That is what the defaultArg function is for: it takes a 'T option, and a 'T representing the default value to return if your value is None, and it returns a plain 'T.
So to sum up:
Seq.tryFind takes a predicate function and a sequence, and returns a 'T option. In your case, this will be a string option
defaultArg takes a 'T option and a default value, and returns a normal 'T (in your case, a string).
With these two pieces, plus a predicate function you can write yourself, we can do what you're looking for.
One more note before I show you the code: you wrote let getIP : string = (code). It seems like you intended for getIP to be a function, but you didn't give it any parameters. Writing let something = (code block) will create a value by running the code block immediately (and just once) and then assigning its result to the name something. Whereas writing let something() = (code block) will create a function. It will not run the code block immediately, but it will instead run the code block every time the function is called. So I think you should have written let getIP() : string = (code).
Okay, so having explained all that, let's put this together to give you a getIP function that actually works:
let getIP() = // No need to declare the return type, since F# can infer it
let isInternet ip = // This is the predicate function
// Note that this function isn't accessible outside of getIP()
ip.AddressFamily = AddressFamily.InterNetwork
let host = Dns.GetHostEntry(Dns.GetHostName())
let maybeIP = Seq.tryFind isInternet host.AddressList
defaultArg maybeIP "?"
I hope that's clear enough; if there's anything you don't understand, let me know and I'll try to explain further.
Edit: The above has one possible flaw: the fact that F# may not be able to infer the type of the ip argument in isInternet without an explicit type declaration. It's clear from the code that it needs to be some class with an .AddressFamily property, but the F# compiler can't know (at this point in the code) which class you intend to pass to this predicate function. That's because the F# compiler is a single-pass compiler, that works its way through the code in a top-down, left-to-right order. To be able to infer the type of the ip parameter, you might need to rearrange the code a little, as follows:
let getIP() = // No need to declare the return type, since F# can infer it
let host = Dns.GetHostEntry(Dns.GetHostName())
let maybeIP = host.AddressList |> Seq.tryFind (fun ip -> ip.AddressFamily = AddressFamily.InterNetwork)
defaultArg maybeIP "?"
This is actually more idiomatic F# anyway. When you have a predicate function being passed to Seq.tryFind or other similar functions, the most common style in F# is to declare that predicate as an anonymous function using the fun keyword; this works just like lambdas in C# (in C# that predicate would be ip => ip.AddressFamily == AddressFamily.InterNetwork). And the other thing that's common is to use the |> operator with things like Seq.tryFind and others that take predicates. The |> operator basically* takes the value that's before the |> operator and passes it as the last parameter of the function that's after the operator. So foo |> Seq.tryFind (fun x -> xyz) is just like writing Seq.tryFind (fun x -> xyz) foo, except that foo is the first thing you read in that line. And since foo is the sequence that you're looking in, and fun x -> xyz is how you're looking, that feels more natural: in English, you'd say "Please look in my closet for a green shirt", so the concept "closet" comes up before "green shirt". And in idiomatic F#, you'd write closet |> Seq.find (fun shirt -> shirt.Color = "green"): again, the concept "closet" comes up before "green shirt".
With this version of the function, F# will encounter host.AddressList before it encounters fun ip -> ..., so it will know that the name ip refers to one item in host.AddressList. And since it knows the type of host.AddressList, it will be able to infer the type of ip.
* There's a lot more going on behind the scenes with the |> operator, involving currying and partial application. But at a beginner level, just think of it as "puts a value at the end of a function's parameter list" and you'll have the right idea.
In F# any if/else/then-statement must evaluate to the same type of value for all branches. Since you've omitted the else-branch of the expression, the compiler will infer it to return a value of type unit, effectively turning your if-expression into this:
if ip.AddressFamily = AddressFamily.InterNetwork then
ip.ToString() // value of type string
else
() // value of type unit
Scott Wlaschin explains this better than me on the excellent F# for fun and profit.
This should fix the current error, but still won't compile. You can solve this either by translating the C#-code more directly (using a mutable variable for the localIP value, and doing localIP <- ip.ToString() in your if-clause, or you could look into a more idiomatic approach using something like Seq.tryFind.

F# how to handle nullable types

I try to do some graphs in F#. As an input I have CSV file that has some values nullable (e.g. nullable int). I try to show chart with following code :
[for row in data.Rows -> row.A.Value, row.B.Value] |> Chart.Point
Where both A and B are nullable integers. I received following error
System.InvalidOperationException: Nullable object must have a value.
How I should handle nullable types. Should I write some Option type to handle it or there is some other good way how to solve it.
If you are using F# 4.0, then there is a built-in function Option.ofNullable. If no, then you can use the implementation in the other answer.
You can also use the same code to define an active pattern:
let (|Present|_|) (n:System.Nullable<_>) =
if n.HasValue then Some(n.Value)
else None
... this can be used inside a match construct and so you can write:
[ for row in data.Rows do
match row.A, row.B wih
| Present a, Present b -> yield a,b
| _ -> () ] |> Chart.Point
Where you are going wrong is: you are calling the Value property on something that might be null.
When you call Value you are effectively saying "It's okay, I have rigorously changed this value and it's definitely not null so it's perfectly safe to treat it as if it were a non-nullable value." Of course, in this case, that condition isn't met, hence the runtime exception.
In F#, you don't want to be working with Nullable<'T> types, you want to be working with Option<'T>, this is much safer and the compiler can check more effectively that you're not making a mistake.
You can convert from Nullable<'T> to Option<'T> for the list using
[for row in data.Rows -> Option.ofNullable (row.A), Option.ofNullable(row.B)]
Of course then you have to decide how you want to handle the None cases but it's much easier to do that once you've made your design explicitly tell you that you've got a value that may or may not be something.
I don't know what behaviour you want but, as an example, perhaps you want to only chart the cases where both values are valid?
You could zip two option values:
module Option =
let zip a b =
match (a,b) with
|Some sa, Some sb -> Some(sa, sb)
|_ -> None
You can then map back to plotable numbers, extracting the None cases using List.choose.
[for row in data.Rows -> Option.ofNullable (row.A), Option.ofNullable (row.B)]
|> List.choose (fun (a,b) -> Option.zip a b)
|> Chart.Point
Map the Nullable type to Option type and filter them out (with .filter or .choose) or transform the None's to a special value for missing values (e.g. 0, -1, NaN) depending on your data to make them working in the charting tool.
module Option =
let fromNullable (n: _ Nullable) =
if n.HasValue
then Some n.Value
else None

Currying functions with format dependent types

As far as I'm aware, F# doesn't handle printfn like it does other functions because of it's type dependence on the string parameter. Could someone explain to me why that prevents me from doing
let printn = printfn "%A"
The error says the type is infered to ('a -> unit) and that I need to add an explicit parameter or a type annotation. Why? I'm perfectly fine with the type it inferred it to. Also, if I add an explicit point, it still has the same type.
Because printn would be a simple value the way you define it. And values can't be generic in the .NET runtime.
Make the parameter explicit so it is a function:
let printn value = printfn "%A" value
For more information, see the topic Value Restriction on MSDN.

Why F# fails to infer types as C# would do

From the book by Tomas Petricek the following code doesn't work as compiler is unable to infer the type of the dt parameter:
> Option.map (fun dt -> dt.Year) (Some(DateTime.Now));;
error FS0072: Lookup on object of indeterminate type.
And if we specify type explicitly everything works fine:
> Option.map (fun (dt:DateTime) -> dt.Year) (Some(DateTime.Now));;
val it : int option = Some(2008)
Or we can use pipelining operator to "help" compiler to infer type:
> Some(DateTime.Now) |> Option.map (fun dt -> dt.Year);;
val it : int option = Some(2008)
The question is why F# compiler can't infer the type of the dt parameter? In this particular case it looks quite easy to infer the dt's type.
The logic behind it can be the following:
the signature of Option.map is map : ('T -> 'U) -> 'T option -> 'U option
the type of the last parameter is DateTime option
so our map usage looks like map : ('T -> 'U) -> 'DateTime option -> 'U option
the compiler then can try to substitute DateTime as 'T to see if it would be correct, so we have (DateTime -> 'U) -> 'DateTime option -> 'U option
then it can infer the 'U type by looking at the body of the lambda-function, so the 'U becomes int
and we finally have (DateTime -> int) -> 'DateTime option -> 'int option
So why F# can't do this inference? Tomas mentions in his book that F# infers types by going from the first to the last argument and that's why the order of arguments matters. And that's why F# can't infer the types in the first example. But why F# can't behave like C#, i.e. try to infer types incrementally starting with what is known?
In most cases F# is much more powerful when speaking about type inference... that't why I'm confused a bit.
So why F# can't do this inference?
F# could do that as OCaml does that. The disadvantage of this kind of more sophisticated inference is the obfuscation of error messages. OCaml taught us that the result generated such incomprehensible errors that, in practice, you always resort to annotating types in order to prevent the compiler from being led down a type inference garden path. Consequently, there was little motivation to implement this in F# because OCaml had already shown that it is not very pragmatic.
For example, if you do that in OCaml but mis-spell the method name then you will get a huge error message at some later point in the code where two inferred class types mismatch and you will have to hunt through it to find the discrepancy and then search back through your code to find the actual location of the error.
IMO, Haskell's type classes also suffer from an equivalent practical problem.
F# can do everything C#'s type inference can do...and much, much more. AFAIK, the extent of C#'s type inference is auto-typing a variable based on the right-hand side of an assignment.
var x = new Dictionary<string, int>();
The equivalent F# would be:
let x = Dictionary()
or
let x = Dictionary<_,_>()
or
let x = Dictionary<string,_>()
or
let x = Dictionary<string,int>()
You can provide as much or as little type information as you want, but you would almost never declare the type of x. So, even in this simple case, F#'s type inference is obviously much more powerful. Hindley-Milner type inference types entire programs, unifying all the expressions involved. As far as I can tell, C# type inference is limited to a single expression, assignment at that.

Resources