我试图了解Haskell类型推断和类型系统的工作原理。现在,我正在研究(sequence .) . fmap
的情况。我可以像haskell一样得到(sequence .)
和(. fmap)
的类型:
(.) :: (b -> c) -> (a -> b) -> a -> c
fmap :: Functor f => (a -> b) -> f a -> f b
sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
-- Type for . fmap:
a ~ (a -> b)
b ~ (f a -> f b)
. fmap :: ((f a -> f b) -> c) -> ((a -> b) -> c)
-- Type for sequence:
b ~ t (m a1)
c ~ m (t a2)
sequence . :: (a1 -> t (m a2)) -> (a1 -> m (t a2))
但是我不能得到(sequence .) . fmap
的类型。我尝试按照以下步骤操作,然后卡住了:
(sequence .) . fmap - ?
f a ~ a1
f b ~ t (m a2)
b ~ m a2
c ~ (a1 -> m (t a2))
(sequence .) . fmap :: (a -> m a2) -> (a1 -> m (t a2))
我得到的类型与haskell给出的类型不同。
UPD 多亏了@WillemVanOnsem,我取得了一些进步,但后来又卡住了...
(.) :: (b -> c) -> (a -> b) -> a -> c
(fmap) :: Functor f => (z -> u) -> f z -> f u
sequence . :: (a1 -> t (m a2)) -> (a1 -> m (t a2))
b ~ (a1 -> t (m a2))
c ~ (a1 -> m (t a2))
a ~ (z -> u)
(sequence .) . fmap :: ((a1 -> t (m a2)) -> (a1 -> m (t a2))) ->
((z -> u) -> (a1 -> t (m a2))) ->
((z -> u) -> (a1 -> m (t a2))
答案 0 :(得分:1)
已经晚了,但我还是想回答。
这些是我理解.).
实际上,需要的不是类型推断,我们需要了解替换步骤,类型推断只会产生影响。
正如在一条评论中指出的,假设的变电站是不正确的。
变电站步骤(序列 .)。 fmap
sequence .
-- (.)
组合运算符将 sequence
作为左参数(sequence .) .
-- 外部 (.)
将 (sequence .)
作为左参数(sequence .) . fmap
-- 外层 (.)
将 fmap
作为右参数为什么我们甚至首先需要 .).
举个简单的例子 如果我想先用两个参数组合 2 个函数,然后用一个参数组合第二个函数怎么办
这里我举了一个简单的例子
i' :: Int -> Int -> String
i' x = show . (x +)
替换顺序
show .
-- (.)
将 show
作为左参数x +
-- (+)
将 x
作为左参数show . (x +)
-- (.)
将 (x +)
作为正确的参数如果我们喜欢制作无点怎么办?
在这里
i :: Int -> Int -> String
i = (show .) . (+)
替换顺序
show .
-- (.)
将 show
作为左参数(show .) .
-- 外部 (.)
将 (show .)
作为左参数(show .) . (+)
-- (.)
将 (x)
作为正确的参数我们甚至可以为它创建一个运算符
(.~.) :: (b -> c) -> (a1 -> a2 -> b) -> a1 -> a2 -> c
f .~. g = (f .) . g -- wish I could name it (..)
并像这样使用它
f :: (Monad m, Traversable t) => (a1 -> m a) -> t a1 -> m (t a)
f = sequence .~. fmap
所以 .).
只不过是 (f .)
在正确的参数中采用 . g
而 g 将采用 2 个参数。
顺便说一句,没有什么能阻止我们
jj ::(Show b)=> (a1 -> a2 -> a3 -> b) -> a1 -> a2 -> a3 -> String
jj = (((show .) . ) . someFunctionWithThreeArguments
答案 1 :(得分:0)
让我们的类型变量保持不同。
(.) :: (b -> c) -> (a -> b) -> a -> c
fmap :: Functor f => (u -> v) -> f u -> f v
sequence :: (Traversable t, Monad m) => t (m x) -> m (t x)
函数.
有两种用法。我将为第一个使用a1
等,第二个使用a2
等。
在(sequence .)
中,我们有(b1 -> c1) = (t (m x) -> m (t x))
,所以b1 = t (m x)
和c1 = m (t x)
。通过使用替换,.
专用于(t (m x) -> m (t x)) -> (a1 -> t (m x)) -> a1 -> m (t x)
,在应用于sequence
之后,我们得到了类型为(a1 -> t (m x)) -> a1 -> m (t x)
的术语。
现在我们可以看看第二个.
,(sequence .) . fmap
。在这里,我们有(b2 -> c2) = (a1 -> t (m x)) -> a1 -> m (t x)
和(a2 -> b2) = (u -> v) -> f u -> f v
。
这意味着:
b2 = a1 -> t (m x)
c2 = a1 -> m (t x)
a2 = (u -> v)
b2 = f u -> f v
请注意,我们在该位置有两次b2
,这意味着分别是a1 = f u
和t (m x) = f v
,因此我们也可以得出f = t
,v = m x
。 / p>
现在我们知道所有这些类型,我们知道第二个.
专用于
((t u -> t (m x)) -> (t u -> m (t x))
-> ((u -> m x) -> (t u -> t (m x)))
-> (u -> m x)
-> (t u -> m (t x))
但是我们已经应用了.
的两个参数,因此整个表达式的类型为(u -> m x) -> (t u -> m (t x))
。
从那里开始,它只是ghci给我的东西之外的变量重命名,约束和括号。
> :t (sequence .) . fmap
(sequence .) . fmap
:: (Monad m, Traversable t) => (a1 -> m a) -> t a1 -> m (t a)