Confusing F# compiler message

101 views Asked by At

The following snippet illustrates the error I'm getting. Even though both match branches return the same thing; I get error, "This expression was expected to have type unit but here has type 'a -> unit" I have no clue what the compiler wants here...

open System.IO 

let FileContent contents =  
  match contents with  
  | "" -> None  
  | c -> Some(c)  

let WriteSomething (contents:string) =  
  let writer = new StreamWriter("")  
  writer.Write( contents ) |> ignore  

let DoStuffWithFileContents =  
  let reader = new StreamReader( "" )  
  let stuff = reader.ReadToEnd()  
  match stuff |> FileContent with  
  | Some(c) -> WriteSomething c  
               |> ignore  
  | None -> ignore  // <- error on "ignore"
2

There are 2 answers

0
p.s.w.g On BEST ANSWER

The ignore operator is actually a function that takes a single input and returns the unit type (F#'s equivalent of void). So when you have -> ignore you're returning the ignore function.

Instead, use () to represent the value of the unit type:

  | Some(c) -> WriteSomething c  
               |> ignore  
  | None -> ()

But actually, since StreamWriter.Write returns void, all these ignore's are unnecessary. You could just as easily write this as:

let WriteSomething (contents:string) =  
  let writer = new StreamWriter("")  
  writer.Write(contents)   

let DoStuffWithFileContents =  
  let reader = new StreamReader("")  
  let stuff = reader.ReadToEnd()  
  match stuff |> FileContent with  
  | Some(c) -> WriteSomething c  
  | None -> () 

Or even better, use Option.iter:

let WriteSomething (contents:string) =  
  let writer = new StreamWriter("")  
  writer.Write(contents)

let DoStuffWithFileContents =  
  let reader = new StreamReader("")  
  let stuff = reader.ReadToEnd()  
  stuff |> FileContent |> Option.iter(WriteSomething)
0
DuckMaestro On

By returning ignore on your last line you are returning a function, not a simple value.

The point of ignore is to convert things to (). Your last line can simply return () directly.