Haskell 类型推断
Haskell 类型推断
理论
类型推断
编译阶段推断类型, 推断规则:
基础类型由类型声明得到
其他类型由算法推断得到
Ambiguous Type
Ambiguous Type: 无法通过 context 推断出类型变量具体类型
-
类型约束的类型变量有默认类型
-
默认类型不适用于高阶类型变量
案例
fmap id == id
== :: Functor f => (f a -> f a) -> (f a -> f a) -> Bool
fmap id :: Functor f => f a -> f a
id :: Functor f => f a -> f a
错误1 Ambiguous Type variable 未明确的类型变量
类型变量 f (错误信息中的 f0)不能明确
fmap id
fmap :: Functor f => (a->b) -> f a -> f b
id :: c -> c
c -> c = a -> b
所以 a = b = c
fmap :: Functor f => (a -> a) -> f a -> f a
fmap id :: Functor f => f a -> f a
fmap id [1,2,3]
fmap :: Functor f => (a->b) -> f a -> f b
id :: c -> c
[1,2,3] :: Num d => [d]
c -> c = a -> b
所以 a = b = c
[d] = f a
所以 f = [], a = d
fmap :: Num a => (a->a) -> [] a -> [] a
fmap id [1,2,3] :: Num a => [a]
\(~\)
错误2 Eq 类型类无函数 instance
fmap id == id
表达式两侧类型推断为 f0 b0 -> f0 b0
, 不是 Eq 类型类的 instance, 不能使用 ==
class Eq a where
== :: a -> a -> Bool
\(~\)
map (+)
与 map +
map (+) :: Num a => [a] -> [a -> a]
map + :: Num ((a -> b) -> [a] -> [b]) => ((a -> b) -> [a] -> [b]) -> (a -> b) -> [a] -> [b]
map (+)
map :: (a -> b) -> [a] -> [b]
(+) :: Num c => c -> c -> c
map (+) 中 (+) 为前缀函数, 优先级与 map 相同, 隐式括号 (map (+)), 按结合性从左到右, + 作为 map 的第一个参数
Num c => c -> c -> c = a -> b
由 -> 的结合性
得 a = c, b = c -> c
map (+) :: Num a => [a] -> [a -> a]
map +
map :: (a -> b) -> [a] -> [b]
(+) :: Num c => c -> c -> c
map + 中 + 为中缀函数, 优先级比 map 低, 隐式括号 ((map) +), map 作为 + 的第一个参数
Num c => c = (a -> b) -> [a] -> [b]
map + :: Num ((a -> b) -> [a] -> [b]) => -> ((a -> b) -> [a] -> [b]) -> (a -> b) -> [a] -> [b]
(+) <$> (+2) <*> (*3)
共享环境 r
(r+2)
作为 (+)
的第一个参数
(+) <$> (+2)
<$> :: (a -> b) -> (r -> a) -> (r -> b)
(+) :: Num a => a -> a -> a
(+2) :: NUm r => r -> r
r = a, b = a -> a
(+) <$> (+2) :: Num r => r -> r -> r
(+) <$> (+2) = \x -> (x+2) +
r*3
作为 (+)
的第二个参数
(+) <$> (+2) <*> (*3)
<*> :: (r -> a -> b) -> (r -> a) -> (r -> b)
(+) <$> (+2) :: Num r => r -> r -> r
(*3) :: Num r => r -> r
r = a = b
(+) <$> (+2) <*> (*3) :: Num r => r -> r
(+) <$> (+2) <*> (*3) = \x -> (x+2) + (x*3) -- 结果
练习: (\x y z -> [x,y,z]) <$> (+1) <*> (*2) <*> (/3) $ 4
共享环境 r
r+1
作为 (\x y z -> [x,y,z])
的第一个参数
<$> :: (a -> b) -> (r -> a) -> r -> b
(\x y z -> [x,y,z]) :: x -> y -> z -> m
(+1) :: Num r => r -> r
x = a = r, b = y -> z -> m
(\x y z -> [x,y,z]) <$> (+3) :: Num r => r -> y -> z -> m
(\x y z -> [x,y,z]) <$> (+3) = \x -> \y z -> [x + 1, y z]
r*2
作为 (\x y z -> [x,y,z]) <$> (+1)
的第二个参数, 即 (\x y z -> [x,y,z])
的第二个参数
<*> :: (r -> a -> b) -> (r -> a) -> r -> b
(\x y z -> [x,y,z]) <$> (+1) :: Num r => r -> y -> z -> m
(*2) :: Num r => r -> r
y = a = r, b = z -> m
(\x y z -> [x,y,z]) <$> (+1) <*> (*2) :: Num r => r -> z -> m
(\x y z -> [x,y,z]) <$> (+1) <*> (*2) = \x -> \z -> [x + 1, x * 2, z]
r/3
作为 (\x y z -> [x,y,z]) <$> (+1) <*> (*2)
的第二个参数, 即 (\x y z -> [x,y,z])
的第三个参数
<*> :: (r -> a -> b ) -> (r -> a) -> r -> b
(\x y z -> [x,y,z]) <$> (+1) <*> (*2) :: r -> z -> m
(/3) :: Num r => r -> r
z = a = r, b = m
(\x y z -> [x,y,z]) <$> (+1) <*> (*2) <*> (/3) :: Num r => r -> [r, r, r]
(\x y z -> [x,y,z]) <$> (+1) <*> (*2) <*> (/3) = \x -> [x+1, x*2, x/3]
(\x y z -> [x,y,z]) <$> (+1) <*> (*2) <*> (/3) $ 4
4 带入函数 \x -> [x+1, x*2, x/3]
为 [5, 8, 1.3333333]
(.) $ (.)
类型推断
初始类型
(.) :: (b1 -> c1) -> (a1 -> b1) -> a1 -> c1
$ :: (x -> y) -> x -> y
(.) :: (b2 -> c2) -> (a2 -> b2) -> a2 -> c2
类型统一
x -> y = (b1 -> c1) -> (a1 -> b1) -> a1 -> c1
x = (b2 -> c2) -> (a2 -> b2) -> a2 -> c2
x = b1 -> c1 = (b2 -> c2) -> (a2 -> b2) -> a2 -> c2
y = (a1 -> b1) -> a1 -> c1
b1 = b2 -> c2
c1 = (a2 -> b2) -> a2 -> c2
最终类型
(a1 -> b1) -> a1 -> c1
= (a1 -> b2 -> c2) -> a1 -> (a2 -> b2) -> a2 -> c2
(.) $ (.)
最终类型为 (a1 -> b2 -> c2) -> a1 -> (a2 -> b2) -> a2 -> c2
通过类型来判断(猜测) (.) $ (.)
表达式
(.) $ (.) :: (a1 -> b2 -> c2) -> a1 -> (a2 -> b2) -> a2 -> c2
(.) $ (.) = \f x g y -> f x (g y)
表达式归约
初始表达式
(.) = \h f x -> h (f x)
$ = \m n -> m n
(.) = \k g y -> k (g y)
归约
(.) $ (.) = (\m n -> m n) (\h f x -> h (f x)) (\k g y -> k (g y))
= (\h f x -> h (f x)) (\k g y -> k (g y)) -- β 归约
= \f x -> (\k g y -> k (g y)) (f x) -- β 归约
= \f x -> \g y -> (f x) (g y) -- β 归约
= \f x g y -> f x (g y) -- 简写约定
(.) $ (.)
类型及表达式
(.) $ (.) :: (a1 -> b2 -> c2) -> a1 -> (a2 -> b2) -> a2 -> c2
(.) $ (.) = \f x g y -> f x (g y)
参数
(.) $ (.)
参数 f x g y
f
是左(.)
的第二个参数x
是左(.)
的第三个参数g
是右(.)
的第二个参数y
是右(.)
的第三个参数
理解
理解 (.) $ (.)
参数 \f x g y
与结果表达式 f x (g y)
整体层面左(.)
左 (.)
的第一个参数由右 (.)
占据, 于是还需要输入第二第三参数 f
和 x
, 这是 \f x
的由来
左 (.)
的三个参数都得到了满足, 分别是 右(.)
和 f
和 x
, 左 (.)
作用于满参数的表达式则是 右(.) (f x)
内部层面右(.)
整体表达式为 右(.) (f x)
显然还缺两个参数
右 (.)
的第一个参数由 (f x)
占据, 于是还需要输入第二第三参数 g
和 y
, 这是 \g y
的由来
右 (.)
的三个参数都得到了满足, 分别是 (f x)
和 g
和 y
, 右 (.)
作用于满参数的表达式则是 (f x) (g y)
, 即 f x (g y)
, 这也是整体表达式补全剩余参数 g
和 y
后的结果
总结
于是整体需要参数 \f x g y
, 表达式 f x (g y)
(.) $ (.) :: (a1 -> b2 -> c2) -> a1 -> (a2 -> b2) -> a2 -> c2
(.) $ (.) = \f x g y -> f x (g y)
示例
((.) $ (.)) (==) 1 (1+) 0
True
(.) . (.)
类型推断
初始类型
(.) :: (b1 -> c1) -> (a1 -> b1) -> a1 -> c1
. :: (b2 -> c2) -> (a2 -> b2) -> a2 -> c2
(.) :: (b3 -> c3) -> (a3 -> b3) -> a3 -> c3
类型统一
b2 -> c2 = (b1 -> c1) -> (a1 -> b1) -> a1 -> c1
a2 -> b2 = (b3 -> c3) -> (a3 -> b3) -> a3 -> c3
b2 = b1 -> c1
c2 = (a1 -> b1) -> a1 -> c1
a2 = b3 -> c3
b2 = (a3 -> b3) -> a3 -> c3
b1 = a3 -> b3
c1 = a3 -> c3
最终类型
a2 -> c2
= (b3 -> c3) -> (a1 -> b1) -> a1 -> c1
= (b3 -> c3) -> (a1 -> a3 -> b3) -> a1 -> a3 -> c3
(.) . (.)
类型为 (b3 -> c3) -> (a1 -> a3 -> b3) -> a1 -> a3 -> c3
表达式归约
初始表达式
(.) = \f g y -> f (g y)
. = \h k x -> h (k x)
(.) = \m n z -> m (n z)
归约
(.) . (.) = (\h k x -> h (k x)) (\f g y -> f (g y)) (\m n z -> m (n z))
= \x -> (\f g y -> f (g y)) (\n z -> x (n z)) -- β 归约
= \x -> \g y -> (\n z -> x (n z)) (g y) -- β 归约
= \x -> \g y -> \z -> x (g y z) -- β 归约
= \x g y z -> x (g y z) -- 简写约定
(.) . (.)
类型及表达式
(.) . (.) :: (b3 -> c3) -> (a1 -> a3 -> b3) -> a1 -> a3 -> c3
(.) . (.) = \x g y z -> x (g y z)
参数
(.) . (.)
参数 \x g y z
x
是.
的第三个参数g
是左(.)
的第二个参数y
是左(.)
的第三个参数z
是右(.)
的第三个参数
理解
理解 (.) . (.)
参数 \x g y z
与结果表达式 x (g y z)
整体 (.) . (.)
. :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)
中间 .
的前两个参数 (.)
得到满足, 需要第三个参数, 这是 \x
的由来
整体表达式 左(.) . 右(.) = \x -> 左(.) (右(.) x)
表达式 左(.) (右(.) x)
左(.)
第一个参数 (右(.) x
) 得到满足, 还需要第二第三两个参数, 这是 \g y
的由来, 从而
左(.) (右(.) x) = \g y -> (右(.) x) (g y)
即 左(.) (右(.) x) = \g y -> 右(.) x (g y)
表达式 右(.) x (g y)
右(.)
前两个参数分别是 x
和 (g y)
得到满足, 还需要第三个参数, 这是 \z 的由来, 从而
右(.) x (g y) = \z -> x (g y z)
整合, 参数按序依次为 \x g y z
, 表达式为 x (g y z)
(.) . (.) :: (b3 -> c3) -> (a1 -> a3 -> b3) -> a1 -> a3 -> c3
(.) . (.) = \x g y z -> x (g y z)
示例
((.) . (.)) (*3) (+) 1 2
9