-1

I'm trying to write a string list to a file using WriteAllLines from the .Net library. I'm getting an error on the last line

"Block following this let is unfinished. Expect an expression." I'm looking at this for an hour now, cant find anything out. Can someone help?

let rec ConvertToString list =
   match list with
   | [l] -> l.ToString()
   | head :: tail -> head.ToString() + ConvertToString tail
   | [] -> ""


let rec WriteImage(filepath:string, width:int, height:int, depth:int, image:int list list) = 
  if image = [] then 
   System.IO.File.WriteAllLines(filepath, L)
   true  // success
  else 
   let L = ConvertToString(image.Head) :: WriteImage(filepath, width, height, depth, image.Tail)
user3507072
  • 287
  • 1
  • 4
  • 13
  • Both sides of `if` need to return something. The second one does not return anything – John Palmer Feb 25 '15 at 03:57
  • I don't want to return anything though. I just want this list L to grow recursively until the image is empty. Or should I be returning something that I'm not understanding? – user3507072 Feb 25 '15 at 04:02
  • Related links - [Block is unfinished](https://stackoverflow.com/q/5055946/465053) and [“let is unfinished. expect an expression” error. I don't see where though](https://stackoverflow.com/q/35617872/465053) – RBT May 16 '18 at 00:43

1 Answers1

0

Blocks of F# code are expressions and they can not finish with a let bind assignment, that's the first thing the compiler tells you.

In F# all functions are expressions and they should return something, you can make your code returns nothing by returning the unit value () so you can remove the let L = in the last line, and it makes sense, otherwise what are you doing with L? It's the last line.

But apart from that you have more errors:

  • In that last line you are trying to list-concatenate a string with the rec call to the function which returns a boolean. You can't concatenate a string with a boolean. A string can be concatenated with a list of strings. So you need an additional parameter to be called initially with an empty string.

  • WriteAllLines accept an array, not a list, you need to add a conversion.

  • You say you don't want to return anything, which makes sense but in the first branch you are returning true that makes no sense and will not type check, just remove that line.

  • The first case in the match of the function ConvertToString it's trying to convert a single element list to a string. You don't need that case, the other 2 cases will be sufficient.

Here's your code after those corrections:

let rec ConvertToString list =
   match list with
   //| [l] -> l.ToString()
   | head :: tail -> head.ToString() + ConvertToString tail
   | [] -> ""

let rec WriteImage strList (filepath:string, width:int, height:int, depth:int, image:int list list) = 
  if image = [] then 
   System.IO.File.WriteAllLines(filepath, List.toArray strList)
   // true  // success
  else 
   WriteImage (ConvertToString(image.Head)::strList) (filepath, width, height, depth, image.Tail)

// then you call your function this way
WriteImage "" (filepath, width, height, depth, image)

One more thing, the parameters width, height, depth don't play any role in the body of the function, you can remove them all.

Finally if you are learning it's a good exercise to become familiar with recursion as a first step, but in fact you don't need it at all in this case since you can use higher order functions like List.map . Your code could be rewritten like this:

open System
let writeImage filepath (image:int list list) = 
    let sep = "" // you  may specify a separator here, like " - "
    let convertToString = List.map string >> String.concat sep
    IO.File.WriteAllLines (filepath, image |> List.map convertToString |> List.toArray)

// you can call your code like this
writeImage filepath image
Gus
  • 25,839
  • 2
  • 51
  • 76