Fof*_*Fof 2 haskell types unification
我试图理解为什么类型fun g x = ys where ys = [x] ++ filter (curry g x) ys
的((a, a) -> Bool) -> a -> [a]
.
我明白那个:
filter :: (a -> Bool) -> [a] -> [a]
然后 curry :: ((a, b) -> c) -> a -> b -> c
但我不明白如何继续.
小智 7
下面的方法不一定是最简单或最快的,但它是相对系统的.
严格来说,你正在寻找的类型
\g -> (\ x -> let ys = (++) [x] (filter (curry g x) ys) in ys)
Run Code Online (Sandbox Code Playgroud)
(let
并且where
相同,但有时候更容易推理使用let
),给定类型
filter :: (a -> Bool) -> [a] -> [a]
curry :: ((a, b) -> c) -> a -> b -> c
Run Code Online (Sandbox Code Playgroud)
不要忘记你也在使用
(++) :: [a] -> [a] -> [a]
Run Code Online (Sandbox Code Playgroud)
让我们首先看一下语法树的"最深"部分:
curry g x
Run Code Online (Sandbox Code Playgroud)
我们已经g
和x
之前没有见过,所以我们假设他们有一些类型:
g :: t1
x :: t2
Run Code Online (Sandbox Code Playgroud)
我们也有curry
.在哪里发生的这些功能,类型变量的每一个点(a
,b
,c
)可以有不同的专业,所以这是一个好主意,每次使用这些功能时用新的名称来替代它们.此时,curry
有以下类型:
curry :: ((a1, b1) -> c1) -> a1 -> b1 -> c1
Run Code Online (Sandbox Code Playgroud)
然后我们只能说curry g x
是否可以统一以下类型:
t1 ~ ((a1, b1) -> c1) -- because we apply curry to g
t2 ~ a1 -- because we apply (curry g) to x
Run Code Online (Sandbox Code Playgroud)
那么假设这也是安全的
g :: ((a1, b1) -> c1)
x :: a1
---
curry g x :: b1 -> c1
Run Code Online (Sandbox Code Playgroud)
让我们继续:
filter (curry g x) ys
Run Code Online (Sandbox Code Playgroud)
我们ys
第一次看到,所以让我们暂时保留它ys :: t3
.我们还必须实例化filter
.所以在这一点上,我们知道
filter :: (a2 -> Bool) -> [a2] -> [a2]
ys :: t3
Run Code Online (Sandbox Code Playgroud)
现在我们必须匹配filter
参数的类型:
b1 -> c1 ~ a2 -> Bool
t3 ~ [a2]
Run Code Online (Sandbox Code Playgroud)
第一个约束可以细分为
b1 ~ a2
c1 ~ Bool
Run Code Online (Sandbox Code Playgroud)
我们现在知道以下内容:
g :: ((a1, a2) -> Bool)
x :: a1
ys :: [a2]
---
filter (curry g x) ys :: [a2]
Run Code Online (Sandbox Code Playgroud)
我们继续吧.
(++) [x] (filter (curry g x) ys)
Run Code Online (Sandbox Code Playgroud)
我不会花太多时间来解释[x] :: [a1]
,让我们看看它的类型(++)
:
(++) :: [a3] -> [a3] -> [a3]
Run Code Online (Sandbox Code Playgroud)
我们得到以下约束:
[a1] ~ [a3] -- [x]
[a2] ~ [a3] -- filter (curry g x) ys
Run Code Online (Sandbox Code Playgroud)
由于这些约束可以减少到
a1 ~ a3
a2 ~ a2
Run Code Online (Sandbox Code Playgroud)
我们只是把所有这些a
的a1
:
g :: ((a1, a1) -> Bool)
x :: a1
ys :: [a1]
---
(++) [x] (filter (curry g x) ys) :: [a1]
Run Code Online (Sandbox Code Playgroud)
现在,我将忽略ys
'类型被广泛化,并专注于
\x -> let { {- ... -} } in ys
Run Code Online (Sandbox Code Playgroud)
我们知道我们需要什么类型x
,我们知道它的类型ys
,所以我们现在知道了
g :: ((a1, a1) -> Bool)
ys :: [a1]
---
(\x -> let { {- ... -} } in ys) :: a1 -> [a1]
Run Code Online (Sandbox Code Playgroud)
以类似的方式,我们可以得出结论
(\g -> (\x -> let { {- ... -} } in ys)) :: ((a1, a1) -> Bool) -> a1 -> [a1]
Run Code Online (Sandbox Code Playgroud)
此时,您只需要重命名(实际上,概括,因为您想将它绑定到fun
)类型变量,并且您有答案.