【发布时间】: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 (*)):你在一个元组中配对两个参数,将它们相乘,然后将结果乘以另一个参数。