简体   繁体   中英

How can I properly use pipe and currying in F#?

I'm reading about F# and trying to apply it to my daily job. I was already been able to load a CSV file with the help of FSharp.Data from NuGet, but I did it a imperative style, I think. Now I'm trying to apply functional constructs, tried the following:

open System
open System.IO
open FSharp.Data

[<EntryPoint>]
let main argv =
  let data =
    argv.[0]
    |> Path.Combine Environment.CurrentDirectory
    |> CsvFile.Load

  printfn "%A" data.Headers

  0

What I'm missing here? In my head argv.[0] is passed to the result of Path.Combine Environment.CurrentDirectory which curried already have the current dir as the first path then the combined result is given to CsvFile.Load . Did I get |> and curring wrong?

Because Path.Combine is a C# function which takes a params array, you cannot pipe parameters into the non-zero positions. You can create an array and pass that instead:

[|Environment.CurrentDirectory; argv.[0]|]
|> Path.Combine
|> CsvFile.Load  

Your pipeline looks correct, so I suspect that your issue is that CsvFile.Load is documented to take a URI, not a filename . To check whether you're getting the right filename, I would first replace CsvFile.Load with printfn "Got result: %s" in your pipeline to check whether you're getting the filename you expect. Then if it is what you expect (and I think it will be), you can add another step to the pipeline:

[<EntryPoint>]
let main argv =
  let data =
    argv.[0]
    |> Path.Combine Environment.CurrentDirectory
    |> sprintf "file://%s"  // Convert filename to URI
    |> CsvFile.Load

  printfn "%A" data.Headers

  0

Since you're apparently new to F#, I'll expand those steps a little so you can confirm that your intuition is correct:

    argv.[0]
    |> Path.Combine Environment.CurrentDirectory

This is like calling Path.Combine Environment.CurrentDirectory argv.[0] .

    argv.[0]
    |> Path.Combine Environment.CurrentDirectory
    |> sprintf "file://%s"  // Convert filename to URI

This is like calling sprintf "file://%s" (Path.Combine Environment.CurrentDirectory argv.[0]) .

    argv.[0]
    |> Path.Combine Environment.CurrentDirectory
    |> sprintf "file://%s"  // Convert filename to URI
    |> CsvFile.Load

This is like calling CsvFile.Load (sprintf "file://%s" (Path.Combine Environment.CurrentDirectory argv.[0])) .

From what you said in your question, it looks like this agrees with your understanding because you're understanding pipes correctly. So just pass CsvFile.Load a URI instead of a filename and you should be fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM