【问题标题】:Understanding (Traversable Product) Type了解(可遍历产品)类型
【发布时间】:2019-02-18 17:39:45
【问题描述】:

鉴于fp-course的以下内容:

data Product f g a =
  Product (f a) (g a)

class Functor f where
  -- Pronounced, eff-map.
  (<$>) ::
    (a -> b)
    -> f a
    -> f b

class Functor f => Applicative f where
  pure ::
    a -> f a
  (<*>) ::
    f (a -> b)
    -> f a
    -> f b

我试图为Product f g a 定义Traversable 实例:

instance (Traversable f, Traversable g) =>
  Traversable (Product f g) where
  traverse :: 
    Applicative h =>
    (a -> h b)
    -> Product f g a
    -> h (Product f g b)  
  traverse fn (Product fa ga) = Product (traverse fn fa) (traverse fn ga)

编译器显示错误:

src/Course/Traversable.hs:106:33: error:
    • Occurs check: cannot construct the infinite type: h ~ Product h h
      Expected type: h (Product f g b)
        Actual type: Product h h (f b)

我明白我的定义是怎么错的,但我不明白实际的类型是Product h h (f b)

拆开Product (traverse fn fa) (traverse fn ga)的类型,我相信是:

Product (h (f b)) (h (g b))

因为traverse的签名是Applicative f =&gt; (a -&gt; f b) -&gt; t a -&gt; f (t b)

g 根据Product h h (f b) 的实际类型去哪里?请解释一下上面的实际类型。

【问题讨论】:

  • 您可能会发现使用liftA2Applicative 导出的Applicative 方法)比&lt;$&gt;&lt;*&gt; 更容易定义这个特定实例。我还强烈建议使用打字孔来解决问题:traverse fn (Product fa ga) = _ (traverse fn fa) (traverse fn ga) 会给你一个错误消息,显示你已经得到了什么以及你仍然需要产生什么。
  • 谢谢,@dfeuer!我在 fp-course 上使用过很多类型孔!

标签: haskell


【解决方案1】:

是的。你有

traverse :: (a -> h b) -> f a -> h (f b)
traverse    fn            fa  :: h (f b)   -- and,

traverse :: (a -> h b) -> g a -> h (g b)
traverse    fn            ga  :: h (g b)

因此

Product (traverse fn fa)  (traverse fn ga) :: Product h h (f b)
        (h        (f b))  (h        (g b))

强制等效 f b ~ g bf ~ g 因为 Product p q t 被定义为

Product (p        t    )  (q        t    )
------------------------------------------
       p ~ h   t ~ f b    q ~ h    t ~ g b

因此,显然将Product 应用于两个traverse 结果并没有成功。

但是这两个有h (f b)h (g b)类型,而h是一个Applicative,我们试图用组合类型创建一个h (Product f g b)类型的结果h 的内部,所以如果我们能有的话

         h (f b)           h (g b)              h r              h s
        ---------------------------            ----------------------
         h (Combined  (f b)  (g b))             h (Combined   r    s)

事实上,由于两个bs 是相同的,

        ---------------------------
         h (Combined   f      g b )

所以从foo :: r -&gt; s -&gt; t我们想要得到bar :: h r -&gt; h s -&gt; h t...如果只有such a function ...

baz :: (Applicative h) => (r -> s -> t) -> (h r -> h s -> h t)

...所以答案是liftA2 Product (traverse fn fa) (traverse fn ga),将数据构造函数Product 应用于两个遍历的内部结果“in”“inside” , "under the cover of") 应用:

         h r       h s
           r   ->    s   ->   t
        ------------------------
         h                    t

【讨论】:

  • 我正在尝试帮助某人学习这种“手动类型推断”技术的基础知识。我看到你写了很多这样的东西。您认为您可以指出一个很好的基本示例吗?或者在某处描述如何做到这一点?
  • 我现在不知道,也许 this one,我发现 this searchthese answers 会有所帮助。当然,这一切都归结为 Modus Ponens(有时会有一些变化,比如在这个"monadictype mandala"
  • 所以,基本上,“方法”只是把它写出来in 2D,仔细、缓慢、一致地重命名以避免名称冲突。 (我的一个特别的烦恼是使用 f 来表示 "f"unction 和 "f"unctor...糟糕的东西,那个)。
  • ... 以及 f :: a -&gt; bf (x :: a) :: b 的等价性。 (当然,这也是 Modus Ponens 的事情)。
  • 感谢您挖掘这些内容!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-29
  • 1970-01-01
  • 1970-01-01
  • 2016-06-17
  • 2013-03-11
  • 2021-04-13
  • 1970-01-01
相关资源
最近更新 更多