Haskell-自動モナドインスタンス


8

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

他のクラス(たとえば、表示)では正常に機能しますが、モナドでは機能しません。コンテナをモナドクラスにインスタンス化するようにghciを説得するにはどうすればよいですか?

ありがとう


1
問題はa、それがモナドのインスタンスではないため、あまり意味がありません。たとえばを使用する場合は、のインスタンスなnewtype Container a = Container [a] deriving (Functor, Applicative, Monad)ので機能[]しますMonad
Willem Van Onsem

2
GenerlizedNewtypeDeriving具体的には、ラップされた型のインスタンスを新しい型に「持ち上げる」ためのものです。どのように(またはその場合)Monadインスタンスを自動的に導出できるかという問題Containerは、依然として興味深いものです。(明示的なインスタンスをbase定義するという事実は、あなたができないことを示唆しています。)MonadIdentity
chepner

MonadHaskell標準が自動的に派生できるようにするタイプクラスの1つではありません(Show他のいくつかの基本クラスと一緒に)。GHCは正しい拡張子でそれを行うことができますが、私は信じています。
ロビンジグモンド

@RobinZigmondメッセージGeneralizedNewtypeDerivingが有効であることを示していることに注意してください。問題は、それがまだ機能しない理由です。
アレクセイロマノフ

回答:


9

他のクラスでも問題なく動作します(例:表示)

標準クラスの固定セットのみが、すぐに使用可能な派生をサポートします。

Haskell 98では、派生可能なクラスはEq、Ord、Enum、Ix、Bounded、Read、およびShowのみです。さまざまな言語拡張機能がこのリストを拡張しています。

--- GHCユーザーマニュアル

特にMonad、そのリストにも拡張リストにも属していません。

任意のクラスへの派生を一般化する拡張機能は他にもありますが、100%自動化することはできません。どこかで、その導出方法を指定する必要があります。クラスによっては、基本的に推論できない情報があるため、利用者に負担を強いる場合があります。

あなたの場合、newtype ContainerIdentity標準ライブラリのモナドと表現的に同等なので、次のように使用できますDerivingVia

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

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

この非常に特殊な状況では賢明なインスタンスは1つしかありませんが、ほとんどの場合、インスタンスが1つしかなくても、インスタンスが何であるかを判断するのは簡単ではありません。


また、導出しなければならないFunctorApplicative、その後のタイプの比較Container 3 >>= (+1)ではIdentity 3 >>= (+1)。それが関係しているかどうかわかりDerivingViaません。
chepner

(私が奇妙なことをしている場合、私はを取得Container 3 >>= (+ 1) :: Num (Container b) => Container bIdentity 3 >>= (+ 1) :: Num b => Identity bます。なぜにContainer bではなくb、にNum制約があるのか
わかり

精度をありがとう。2番目の発言については(+ 1) :: Num c => c -> c、Kleisliの矢として持つには、(+ 1) :: a -> Container b統一する必要がありますc ~ Container b。でも、何から始めたらいいのかわからない。
Li-yao Xia

に評価IdentityされるようにContainer、それに対して何が定義されていないのかが疑問に思っIdentity 3 >>= (+1)ていIdentity 4ます。
chepner

それはinstance Num a => Num (Identity a)定義されているからです。
KA Buhr
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.