【问题标题】:How to curry functions in Haskell如何在 Haskell 中对函数进行柯里化
【发布时间】:2019-01-02 12:08:13
【问题描述】:

我有一个函数 multThree 用于将 3 个数字相乘,它适用于柯里化。但是,当我尝试将其扩展到使用相同结构将四个数字相乘时,它不起作用。为什么会这样?如何解决?

multThree :: Num a => a -> (a -> (a -> a))
multThree x = (*) . (*) x

multFour :: Num a => a -> (a -> (a -> (a -> a)))
multFour x = (*) . (*) . (*) x

给出的错误:

• Occurs check: cannot construct the infinite type: a ~ a -> a
  Expected type: a -> a -> a -> a
    Actual type: a -> (a -> a) -> a -> a
• In the expression: (*) . (*) . (*) x
  In an equation for ‘multFour’: multFour x = (*) . (*) . (*) x
• Relevant bindings include
    x :: a (bound at test2.hs:19:10)
    multFour :: a -> a -> a -> a -> a

【问题讨论】:

  • 这与柯里化无关(multThree 已经柯里化了,因为它的类型是 a -> a -> a -> a,而不是 (a, a, a) -> a);它是关于组合高阶函数。
  • multThree 的可怕的无点形式将是multThree = ((*) .) . (*),(老实说)几乎不值得理解,而不是简单地编写非无点版本。 (multFour = ((((*) .) . (*)) .) . (*) 更糟。)
  • 如果你真的想要一个免费的版本,你可以使用multThree = fmap (*) . (*)multFour = fmap (fmap (*)) . fmap (*) . (*) = fmap (fmap (*) . (*)) . (*) = fmap multThree . (*)fmap(.) 相同,但在我看来,它让你“跳过”参数的位置更加清晰。构建无点解决方案的另一种方法是例如multThree = curry ((*) . uncurry (*)):你在一个元组中配对两个参数,将它们相乘,然后将结果乘以另一个参数。

标签: haskell currying


【解决方案1】:

让我们在没有(.)的情况下写出来:

multFour x = (*) . (*) . (*) x
= (*) . (\y -> (y*)) . (x*)
= (\w -> (w*)) . (\z -> ((x*z)*))
= (\w -> (w*)) . (\z v -> x*z*v)
= \z -> \u -> (\v -> x*z*v) * u

所以我们看到我们正在尝试将一个函数乘以一个数字。

关键错误是这样的:

multFour x = (*) . multThree x

种类有:

(*) :: Num a => a -> (a -> a)
multThree x :: Num b => b -> (b -> b)
x :: b
(.) :: (y -> z) -> (x -> y) -> (x -> z)

所以类型统一为:

a = y
z = (a -> a)
b = x
y = b -> b
multFour :: Num b => b -> x -> z
multFour :: (Num b, Num (b -> b)) => b -> b -> (b -> b) -> (b -> b)

这不是您想要的类型。

要修复您的代码,我建议:

multFour a b c d = a * b * c * d

这更具可读性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-22
    • 2010-09-14
    • 2017-05-16
    • 2020-01-28
    相关资源
    最近更新 更多