Haskell 柯里化

Haskell Currying

在过去的两个小时里,我一直在阅读 Haskell 中有关柯里化的内容,所有资源都展示了具有多个参数的函数实际上如何 return 其他函数,但没有介绍它们的定义,所以这就是问题所在。

让我们定义函数:

myFunc :: (Num a) => a -> a -> a
myFunc x y = x * 2 + x * y

:t (myFunc 2) 打印 Num a => a -> a,即一个接受数字并输出数字的函数。但是,(myFunc 2) 编辑的函数 return 的定义是什么样的?编译器是否在定义中替换 x 并且新函数变成类似 myFunc' y = 2 * 2 + 2 * y?

递归如何处理柯里化?如果我定义函数

replicate' :: (Integral i, Ord i) => i -> a -> [a]
replicate' n x
    | n <= 0    = []
    | otherwise = x : replicate' (n - 1) x

,在上下文 (replicate 3) 'a' 中由 (replicate' 3) 编辑的函数 return 是什么?

我认为你混淆了两种不同的东西

  • 柯里化
  • 部分功能应用

第一个是

                      ------currying-----> 
       f :: (a,b) -> c                      f' :: a -> b -> c
                      <----uncurrying-----

将一个接受 元组 个参数的函数转换为一个接受一个参数并生成一个函数的函数!

如果您熟悉线性代数,这与将双线性函数视为产生另一个线性函数的线性函数非常相似。

而部分函数应用只是显式括号化的结果。

f :: a -> b -> c

真的

f :: a -> (b -> c)

至少在 haskell 定义函数的方式中。

这是 replicate' 以显式柯里化形式定义的:

replicate' :: (Integral i, Ord i) => i -> (a -> [a])
replicate' n
   | n <= 0     = const []
   | otherwise  = \x -> x : replicate' (n - 1) x

那么,replicate' 3 的计算结果为表达式

    if 3 <= 0 then const []
              else \x -> x : replicate' 2 x

也就是

  \x -> x : replicate' 2 x

如果它只是用“隐式柯里化”定义的,那么编译器可能会也可能不会从 x 绑定中提取 n <= 0 条件,所以实际上你可能只会得到

    \x -> if 3 <= 0 then const []
                    else \x -> x : replicate' 2 x