haskell中的成分 - 工作方式

时间:2016-06-23 13:18:17

标签: haskell

我无法理解haskell中的作曲方式,
例如:

((.) . (+)) 3 (*2) 9 = 9 * 2 + 3 = 21 这个答案是由ghci产生的 对我来说,应该是:
((.) . (+)) 3 (*2) 9 = (3+9) * 2 类似地,我无法理解为什么((.) . (+))的类型是Num c => c -> (a -> c) -> a -> c

你可以试着解释一下吗?

1 个答案:

答案 0 :(得分:1)

在此表达式中,(.)再次应用于(.)(+)两个参数。让我们一步一步。首先,将(.)部分应用于(.)。我们将明确地写下类型签名,使用不同的类型变量来区分两者:

(.) :: (b -> c) -> (a -> b) -> a -> c
(.) :: (t -> u) -> (s -> t) -> s -> u

现在看一下(.) (.)的类型(部分应用程序)。 (这可能是最棘手的一步,因为所涉及的类型表达式的大小。下一步是相同的,但类型更简单。)第一个参数类型为(b -> c),与{{1}统一},意思是

(t -> u) -> (s -> t) -> s -> u

当我们执行部分应用程序时,我们将第一个参数删除到b ~ t -> u c ~ (s -> t) -> s -> u (因为我们已经给它一个值)并在替换剩余的(.)和{之后查看类型{1}}带有新类型。

b

因为c是右关联的,我们可以删除一些多余的括号来获取

(.)     :: (b -> c) -> (a ->    b   )  -> a ->          c
(.) (.) ::             (a -> (t -> u)) -> a -> ((s -> t) -> s -> u)

现在,我们将 应用于->(同样,为了清晰起见,使用新的类型变量)。 (.) (.) :: (a -> t -> u) -> a -> (s -> t) -> s -> u 的第一个参数的类型为(+) :: Num v => v -> v -> v,我们需要与(.) (.)统一。换句话说,我们会使用a -> t -> u <替换v -> v -> v类型中atu的所有匹配项/ p>

(.) (.)

正如您所看到的(在我们添加v约束之后),这相当于您看到的类型:

(.) (.)     :: (a -> t -> u) -> a -> (s -> t) -> s -> u 
(.) (.) (+) ::                  v -> (s -> v) -> s -> v

对于正在评估的实际表达式,

Num v

请记住-- v ~ c, s ~ a Num v => v -> (s -> v) -> s -> v Num c => c -> (a -> c) -> a -> c

的定义
((.) . (+)) 3 (*2) 9

从左到右工作。首先,(.)适用于f . g = \x -> f (g x)

(.) . (+)

3的部分应用适用于((.) . (+)) 3 == (.) ((+) 3) == (.) (3 +)

.

最后,此功能适用于9:

(* 2)