(跳过手动推导)
求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) 表示,在给定适当的 data 定义的情况下,可能与 Haskell 等效的 Arrow (List (Logvar "a")) (Logvar "a")。
只使用了一个推理规则,即应用程序,以及 Prolog 的结构统一如果 复合术语 具有相同的形状并且它们的成分匹配,则它们匹配:f(a1, a2, ... an) 和 g(b1, b2, ... bm sub>) 匹配当且仅当 f 与 g、n == m 和 ai 相同 匹配 bi,逻辑变量可以根据需要取任何值,但只能 一次 (无法更改)。
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 的操作。我们可以将任何->, (_,_), [] 等纯粹视为句法标记,根本不了解它们的含义,并使用结构统一机械地执行该过程,这里只有一个rule of type inference,即。 应用程序的规则:(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)