我如何获得(sequence。)的类型。 fmap?

时间:2019-01-10 14:33:43

标签: haskell type-systems

我试图了解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))

2 个答案:

答案 0 :(得分:1)

已经晚了,但我还是想回答。

这些是我理解.).

的步骤

实际上,需要的不是类型推断,我们需要了解替换步骤,类型推断只会产生影响。

正如在一条评论中指出的,假设的变电站是不正确的。

变电站步骤(序列 .)。 fmap

  1. sequence . -- (.) 组合运算符将 sequence 作为左参数
  2. (sequence .) . -- 外部 (.)(sequence .) 作为左参数
  3. (sequence .) . fmap -- 外层 (.)fmap 作为右参数

为什么我们甚至首先需要 .).

举个简单的例子 如果我想先用两个参数组合 2 个函数,然后用一个参数组合第二个函数怎么办

这里我举了一个简单的例子

i' :: Int -> Int -> String
i' x = show . (x +)

替换顺序

  1. show . -- (.)show 作为左参数
  2. x + -- (+)x 作为左参数
  3. show . (x +) -- (.)(x +) 作为正确的参数

如果我们喜欢制作无点怎么办?

在这里

i :: Int -> Int -> String
i = (show .) . (+)

替换顺序

  1. show . -- (.)show 作为左参数
  2. (show .) . -- 外部 (.)(show .) 作为左参数
  3. (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 ut (m x) = f v,因此我们也可以得出f = tv = 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)