开发者

Implementing take with F# by translating ML's equivalent

开发者 https://www.devze.com 2023-03-10 19:32 出处:网络
I\'d like to translate this ML code into F#. fun take ([], i) = [] take (x::xs, i) = if i > 0 then x::take(xs, i-1)

I'd like to translate this ML code into F#.

fun take ([], i) = []
  | take (x::xs, i) = if i > 0 then x::take(xs, i-1) 
                                else [];

I tried this one

let rec take n i =
  match n,i with 
    | [], i -> []
    | x::xs, i -> if i > 0 then x::take(xs, i-1)
                           else [];

l开发者_如何转开发et val = take [1;2;3;4] 3

and this one

let rec take input =
  match input with 
    | ([], i) -> []
    | (x::xs, i) -> if i > 0 then x::take(xs, i-1)
                           else [];

let val = take ([1;2;3;4] 3)

But both of them gives me an error take.fs(7,5): error FS0010: Unexpected keyword 'val' in binding. What's wrong with the F# code?


Just to add a few comments, I think the nicest way to write the function in F# is to use:

let rec take i n=  
  match n, i with
  | [], i -> []
  | _, i when i <= 0 -> []
  | x::xs, i -> x::(take (i-1) xs)

I did two changes:

  • Use pattern matching to test whether i <= 0 (which does the same thing as if, but looks a bit nicer)
  • Reverse the order of arguments so that the most important argument (the input list) is the last one. This makes it possible to use the function nicely with pipelining operator:

    [1;2;3;4] |> take 3
    


Since val is a reserved keyword in F#, you can't use it as a value. Your first version of take is wrong because the type of take(xs, i-1) (tuple form) is different from the type of take n i (curried form). This works:

let rec take n i =
  match n, i with 
    | [], i -> []
    | x::xs, i -> if i > 0 then x::(take xs (i-1)) else []

let value = take [1;2;3;4] 3

The second version has a mistake in the way you invoke the function. It could be fixed as follows:

let rec take input =
  match input with 
    | [], i -> []
    | x::xs, i -> if i > 0 then x::take(xs, i-1) else []

let value = take ([1;2;3;4], 3) // Notice ',' as tuple delimiter

Or you can write even closer to your ML function:

let rec take = function 
    | [], i -> []
    | x::xs, i -> if i > 0 then x::take(xs, i-1) else []

let value = take ([1;2;3;4], 3)
0

精彩评论

暂无评论...
验证码 换一张
取 消