Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In F#: How do I obtain a list of the filenames in a directory; expected unit have string

I'm just starting with F# so I thought I would try some simple tasks.

This lists the full paths to the xml files in a directory:

System.IO.Directory.GetFiles("c:\\tmp", "*.xml")
|> Array.iter (printfn "%s")

But I want only the file names so I tried:

System.IO.Directory.GetFiles("c:\\tmp", "*.xml")
|> Array.iter (System.IO.Path.GetFileName)
|> (printfn "%s")

This won't compile. It gives the error:

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

I searched for examples but couldn't find anything. I'm obviously missing something simple and fundamental, but what?

like image 425
Kevin Whitefoot Avatar asked Feb 18 '16 12:02

Kevin Whitefoot


People also ask

What is 1 C equal to in Fahrenheit?

Answer: 1° Celsius is equivalent to 33.8° Fahrenheit.

What does 37.4 Celsius mean in Fahrenheit?

37.4 °C = 99.4 °F 37.6 °C = 99.6 °F. 37.7 °C = 99.8 °F. 37.8 °C = 100.0 °F. 37.9 °C = 100.2 °F.

Whats is in Fahrenheit?

Definition: The Fahrenheit (symbol: °F) is a unit of temperature that was widely used prior to metrication. It is currently defined by two fixed points: the temperature at which water freezes, 32°F, and the boiling point of water, 212°F, both at sea level and standard atmospheric pressure.


1 Answers

Since you are new, one thing to make it easer to fix errors is to think of statements like mathematical statements that can be built up of simpler functions but that can also be factored apart.

So by factoring apart your problem you can get a finer grained error that becomes easier to solve.

System.IO.Directory.GetFiles("c:\\tmp", "*.xml")
|> Array.iter (System.IO.Path.GetFileName)
|> (printfn "%s")

is factored apart into

let directoryArray = System.IO.Directory.GetFiles("c:\\tmp", "*.xml")
let nameArray = Array.iter (System.IO.Path.GetFileName) directoryArray
(printfn "%s") nameArray 

now the errors should be much easier to understand

If we look at the signature of Array.iter which is iter : ('T -> unit) -> 'T [] -> unit we see that it needs a function ('T -> unit) that takes a type and returns a unit which means return nothing, in this case printing would work, however you do not want to return nothing you want to convert the array of directories into an array of filenames. So Array.iter will not work and you need a Array function that applies a function to each item in the array and returns a new Array, Array.map does this map : ('T -> 'U) -> 'T [] -> 'U [] To better understand the Array functions and see how they work one can add a lambda function.

Likewise with (printfn "%s"); one can add a lambda function to pass in a value.

let directoryArray = System.IO.Directory.GetFiles("c:\\tmp", "*.xml")
let nameArray = Array.map (fun x -> (Path.GetFileName(x))) directoryArray
Array.iter (fun x -> printfn "%s" x) nameArray

Now we can simplify the statements using |>

System.IO.Directory.GetFiles("c:\\tmp", "*.xml")
|> Array.map (fun x -> (Path.GetFileName(x)))
|> Array.iter (fun x -> printfn "%s" x)

and simplify again by removing the lambdas

open System.IO

Directory.GetFiles("c:\\tmp", "*.xml") 
|> Array.map Path.GetFileName 
|> Array.iter (printfn "%s") 
like image 188
Guy Coder Avatar answered Nov 15 '22 10:11

Guy Coder