Haskell 类型推断

Haskell 类型推断

理论

类型推断

编译阶段推断类型, 推断规则:

\[\frac{\text{f\ ::\ A -> B\quad\ e\ ::\ A}}{f \ \ e\ ::\ B} \]

基础类型类型声明得到

其他类型算法推断得到

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)

整体层面左(.)

(.) 的第一个参数由右 (.) 占据, 于是还需要输入第二第三参数 fx, 这是 \f x 的由来

(.) 的三个参数都得到了满足, 分别是 右(.)fx, 左 (.) 作用于满参数的表达式则是 右(.) (f x)

内部层面右(.)

整体表达式为 右(.) (f x) 显然还缺两个参数

(.) 的第一个参数由 (f x) 占据, 于是还需要输入第二第三参数 gy, 这是 \g y 的由来

(.) 的三个参数都得到了满足, 分别是 (f x)gy, 右 (.) 作用于满参数的表达式则是 (f x) (g y), 即 f x (g y), 这也是整体表达式补全剩余参数 gy 后的结果

总结

于是整体需要参数 \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
posted @ 2025-04-23 19:22  (.)$(.)  阅读(5)  评论(0)    收藏  举报