(跳过手动推导)
找到head . filter fst
==的类型((.) head) (filter fst)
,给定
head :: [a] -> a
(.) :: (b -> c) -> ((a -> b) -> (a -> c))
filter :: (a -> Bool) -> ([a] -> [a])
fst :: (a, b) -> a
这是通过一个小型 Prolog 程序以纯机械方式实现的:
type(head, arrow(list(A) , A)). %% -- known facts
type(compose, arrow(arrow(B, C) , arrow(arrow(A, B), arrow(A, C)))).
type(filter, arrow(arrow(A, bool), arrow(list(A) , list(A)))).
type(fst, arrow(pair(A, B) , A)).
type([F, X], T):- type(F, arrow(A, T)), type(X, A). %% -- application rule
当在 Prolog 解释器中运行时,它会自动产生,
3 ?- type([[compose, head], [filter, fst]], T).
T = arrow(list(pair(bool, A)), pair(bool, A)) %% -- [(Bool,a)] -> (Bool,a)
其中类型以纯语法方式表示为复合数据项。例如,在给定适当的定义的情况下,类型[a] -> a
由 表示arrow(list(A), A)
,可能与 Haskell 等效。Arrow (List (Logvar "a")) (Logvar "a")
data
仅使用了一个推理规则,即应用程序的推理规则,以及 Prolog 的结构统一,即如果复合词具有相同的形状并且它们的成分匹配,则它们匹配:f(a 1 , a 2 , ... a n )和g (b 1 , b 2 , ... b m )匹配当且仅当f与g , n == m且a i匹配 b i时,逻辑变量可以根据需要取任何值,但只能取一次(无法更改)。
4 ?- type([compose, head], T1). %% -- (.) head :: (a -> [b]) -> (a -> b)
T1 = arrow(arrow(A, list(B)), arrow(A, B))
5 ?- type([filter, fst], T2). %% -- filter fst :: [(Bool,a)] -> [(Bool,a)]
T2 = arrow(list(pair(bool, A)), list(pair(bool, A)))
要以机械方式手动执行类型推断,涉及将事物一个接一个地编写,注意侧面的等价性并执行替换,从而模仿 Prolog 的操作。我们可以将任何->, (_,_), []
等纯粹视为句法标记,根本不了解它们的含义,并使用结构统一机械地执行该过程,这里只有一个类型推断规则,即。应用规则:(在和等价的情况下,将and(a -> b) c ⊢ b {a ~ c}
的并列替换为, )。一致地重命名逻辑变量以避免名称冲突很重要:(a -> b)
c
b
a
c
(.) :: (b -> c ) -> ((a -> b ) -> (a -> c )) b ~ [a1],
head :: [a1] -> a1 c ~ a1
(.) head :: (a ->[a1]) -> (a -> c )
(a ->[c] ) -> (a -> c )
---------------------------------------------------------
filter :: ( a -> Bool) -> ([a] -> [a]) a ~ (a1,b),
fst :: (a1, b) -> a1 Bool ~ a1
filter fst :: [(a1,b)] -> [(a1,b)]
[(Bool,b)] -> [(Bool,b)]
---------------------------------------------------------
(.) head :: ( a -> [ c ]) -> (a -> c) a ~ [(Bool,b)]
filter fst :: [(Bool,b)] -> [(Bool,b)] c ~ (Bool,b)
((.) head) (filter fst) :: a -> c
[(Bool,b)] -> (Bool,b)