通过翻译ML的等价物来实现F#

pro*_*eek 3 f# ml sml take

我想将这个ML代码翻译成F#.

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

我试过这个

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

let val = take [1;2;3;4] 3
Run Code Online (Sandbox Code Playgroud)

还有这个

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)
Run Code Online (Sandbox Code Playgroud)

但他们两个都给我一个错误take.fs(7,5): error FS0010: Unexpected keyword 'val' in binding.F#代码有什么问题?

Tom*_*cek 9

只是添加一些注释,我认为在F#中编写函数的最好方法是使用:

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

我做了两个改动:

  • 使用模式匹配来测试是否i <= 0(它做同样的事情if,但看起来更好)
  • 反转参数的顺序,以便最重要的参数(输入列表)是最后一个.这使得可以很好地使用该功能与流水线操作符:

    [1;2;3;4] |> take 3
    
    Run Code Online (Sandbox Code Playgroud)


pad*_*pad 7

由于val是F#中的保留关键字,因此不能将其用作值.您的第一个版本take是错误的,因为take(xs, i-1)(元组形式)的类型与take n i(咖喱形式)的类型不同.这有效:

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
Run Code Online (Sandbox Code Playgroud)

第二个版本在调用函数时出错.它可以修复如下:

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
Run Code Online (Sandbox Code Playgroud)

或者你可以写得更接近你的ML功能:

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)
Run Code Online (Sandbox Code Playgroud)