【问题标题】:Implementing take with F# by translating ML's equivalent通过翻译 ML 的等价物使用 F# 实现 take
【发布时间】:2023-11-02 19:21:01
【问题描述】:

我想将此 ML 代码翻译成 F#。

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

我试过这个

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

还有这个

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)

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

【问题讨论】:

    标签: f# sml ml take


    【解决方案1】:

    由于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
    

    第二个版本调用函数的方式有误。可以这样修复:

    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
    

    或者您可以编写更接近您的 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)
    

    【讨论】:

    • 第二个版本出现error FS0003: This value is not a function and cannot be applied错误,除了最后的';'外,似乎和我的一样。
    • 不,您应该使用 take ([1;2;3;4], 3) 而不是 take ([1;2;3;4] 3)。注意 ',' 是两个版本的区别。
    【解决方案2】:

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

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

    我做了两个改变:

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

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

    【讨论】:

      最近更新 更多