【问题标题】:Haskell - Automatic Monad instanceHaskell - 自动 Monad 实例
【发布时间】:2020-02-28 18:32:46
【问题描述】:

我正在尝试创建自己的数据类型,它将成为 Monad 类的一部分,但是

newtype Container a = Container a deriving Monad

给我这个错误:

   * Can't make a derived instance of `Monad Container'
        (even with cunning GeneralizedNewtypeDeriving):
        cannot eta-reduce the representation type enough
    * In the newtype declaration for `Container'
   |
30 | newtype Container a = Container a deriving Monad

它适用于其他类(例如 Show),但不适用于 Monad,那么我如何说服 ghci 将我的 Container 实例化为 Monad 类?

谢谢

【问题讨论】:

  • 问题是 a 不是 monad 的实例,因此它没有多大意义。例如,如果您使用newtype Container a = Container [a] deriving (Functor, Applicative, Monad),它将起作用,因为[]Monad 的一个实例。
  • GenerlizedNewtypeDeriving 专门用于将包装类型的实例“提升”到新类型。如何(或是否)可以自动为Container 派生Monad 实例的问题仍然很有趣。 (baseIdentity 显式定义了Monad 实例这一事实表明您不能。)
  • Monad 不是 Haskell 标准可以自动派生的类型类之一(Show 是,以及其他一些基本类型)。不过,我相信 GHC 可以通过正确的扩展来做到这一点。
  • @RobinZigmond 请注意,消息表明GeneralizedNewtypeDeriving 已启用,问题是为什么它仍然不起作用。

标签: haskell instance monads newtype deriving


【解决方案1】:

它适用于其他类(例如显示)

只有一组固定的标准类支持开箱即用的派生:

在 Haskell 98 中,唯一可派生的类是 Eq、Ord、Enum、Ix、Bounded、Read 和 Show。各种语言扩展扩展了这个列表。

--- The GHC User Manual

特别是Monad 不属于该列表,也不属于扩展列表。

还有更多扩展可以推广到任意类,但它们不能 100% 自动化。某个地方的某个人必须指定如何进行推导;根据类别,可能需要用户承担负担,因为存在根本无法推断的信息。

在您的情况下,新类型 Container 在代表性上等同于标准库中的 Identity monad,因此您可以使用 DerivingVia

{-# LANGUAGE DerivingVia #-}
import Data.Functor.Identity

newtype Container a = Container a deriving (Functor, Applicative, Monad) via Identity

在这种非常特殊的情况下,只有一个合理的实例,但大多数情况下,即使只有一个,也很难判断该实例应该是什么。

【讨论】:

  • 您还必须派生FunctorApplicative,然后将Container 3 >>= (+1) 的类型与Identity 3 >>= (+1) 进行比较。我不知道这是否与DerivingVia 有关。
  • (如果我在做一些奇怪的事情,我会得到Container 3 >>= (+ 1) :: Num (Container b) => Container bIdentity 3 >>= (+ 1) :: Num b => Identity b。我不确定为什么Container b,而不是b,有Num 约束.)
  • 感谢您的精确。至于您的第二句话,要将(+ 1) :: Num c => c -> c 用作Kleisli 箭头(+ 1) :: a -> Container b,您需要统一c ~ Container b。但我不确定你的意思是什么。
  • 我只是想知道为Identity 定义的内容是为Container 定义的,因为Identity 3 >>= (+1) 的计算结果为Identity 4
  • 只是因为定义了一个instance Num a => Num (Identity a)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多