【问题标题】:What is wrong with this F# curried function?这个 F# 柯里化函数有什么问题?
【发布时间】:2015-02-18 15:45:32
【问题描述】:

我正在编写这个名为 inner 的 curried f# 函数,它应该将 2 个列表作为参数,并根据位置将两者相乘,然后返回总和:

let rec inner xs = 
    let aux ys = function
    | ([], ys) -> 0
    | (xs, []) -> 0
    | (x::xs, y::ys) -> (x*y) + inner xs ys
    aux ys;;
inner [1;2;3] [4;5;6];;

在这种情况下,答案是 32,因为 1*4 + 2*5 + 3*6 = 32。它有效,但有以下消息:

错误 FS0001:类型不匹配。期待一个
'a list -> 'd
但是给了一个
'b list * 'a list -> int

'a list 类型与'b list * 'a list 类型不匹配

我真的不知道在调用 aux 以使其工作时在旁边放什么。

【问题讨论】:

    标签: f# functional-programming


    【解决方案1】:

    我不确定到底是什么误解。我注意到三个奇怪的点:

    • let aux ys = function ([], ys) -> 声明并立即重新声明,从而隐藏标识符 ys。请注意,aux 是一个带有两个 curried 参数的函数,其中第二个是 2 元组。我怀疑这是你的意图。

    • aux 函数以一种非常不寻常的方式缩进;通常,它应该得到另一个四个空格的缩进。编译器可能不会抱怨这一点,只是在模式匹配后退出作用域,但这会增加对失败行应该做什么的困惑。

    • ys 在上次使用的位置未定义。 (这可能与令人困惑的缩进有关吗?)

    这里有两种写法:

    不是尾递归

    let rec inner xs ys = 
        match xs, ys with
        | x::xt, y::yt -> x * y + inner xt yt
        | _ -> 0
    

    在这个版本中,柯里化的参数被转换成一个元组并用于匹配表达式。 (由于最终添加,这可能会导致大型输入列表的堆栈溢出。)

    尾递归,带辅助函数

    let rec private aux acc = function
        | x::xs, y::ys -> aux (acc + x * y) (xs, ys)
        | _ -> acc
    
    let inner xs ys = aux 0 (xs, ys)
    

    这里,辅助函数有两个柯里化参数,第一个是累加器,第二个是包含两个列表的元组。 inner 成为一个包装函数,它既剥离累加器——通过将其初始化为零——又将元组参数转换为柯里化参数,这是要求的。 (由于递归调用的值为函数返回值,所以该函数支持尾递归编译。)

    【讨论】:

      【解决方案2】:

      您需要在定义aux 函数后调用它。目前你的inner 函数只是定义它,不做任何事情。

      在这种情况下,如果您将 inner 函数定义为采用两个参数,我不确定您是否真的需要定义 aux

      let rec inner (tuple : int list * int list) =
          match tuple with
          | ([], ys) -> 0
          | (xs, []) -> 0
          | (x :: xtail, y :: ytail) -> x * y + inner (xtail, ytail)
      
      inner ([1;2;3], [4;5;6]) // 32
      

      如果您想保留咖喱形式,那么以下应该可以工作。您需要在匹配中包含xs,然后只返回aux(这将包含第一个列表并期望第二个列表):

      let rec inner xs = 
          let aux ys =
              match xs, ys with
              | ([], ys) -> 0
              | (xs, []) -> 0
              | (x::xs, y::ys) -> (x*y) + inner xs ys
          aux
      
      inner [1;2;3] [4;5;6];; // 32
      

      【讨论】:

      • 我试过了,但我不知道在调用它时在 aux 旁边放什么? ys, xs, [],我都试过了!
      猜你喜欢
      • 2019-03-26
      • 1970-01-01
      • 1970-01-01
      • 2019-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-11
      • 1970-01-01
      相关资源
      最近更新 更多