5

私はちょうど頭を無料のモナドに巻きつけようとしていました。学習支援として、私は次のタイプのShowインスタンスを作成することができました。Free

{-# LANGUAGE FlexibleContexts, UndecidableInstances #-}

-- Free monad datatype
data Free f a = Return a | Roll (f (Free f a))

instance Functor f => Monad (Free f) where
    return = Return
    Return a >>= f = f a
    Roll ffa >>= f = Roll $ fmap (>>= f) ffa

-- Show instance for Free; requires FlexibleContexts and
-- UndecidableInstances
instance (Show (f (Free f a)), Show a) => Show (Free f a) where
    show (Return x) = "Return (" ++ show x ++ ")"
    show (Roll ffx) = "Roll (" ++ show ffx ++ ")"


-- Identity functor with Show instance
newtype Identity a = Id a deriving (Eq, Ord)

instance Show a => Show (Identity a) where
    show (Id x) = "Id (" ++ show x ++ ")"

instance Functor (Identity) where
    fmap f (Id x)= Id (f x)


-- Example computation in the Free monad
example1 :: Free Identity String
example1 = do x <- return "Hello"
              y <- return "World"
              return (x ++ " " ++ y)

使用するのはUndecidableInstances少し気になります。それなしで行う方法はありますか?Googleが生み出すのは、Edward Kmettによるこのブログ投稿だけです。このブログ投稿は、基本的に私と同じShowクラス定義を持っています。

4

1 に答える 1

11

またはに対して同じことを行うことはできませんが、実際にはここでUndecidableInstance要件を削除できます。ShowReadEq

秘訣は、ファンクターの内容を、より直接的に表示できるものに置き換えることですが、他の人には知らせません。したがって、エクスポートを次のように制限します。

{-# LANGUAGE FlexibleContexts #-}

module Free (Free(..)) where

そして、私たちにしかできないことのためにデータ型を打ち負かしshowます。

newtype Showable = Showable (Int -> ShowS)

showable :: Show a => a -> Showable
showable a = Showable $ \d -> showsPrec d a

instance Show Showable where
    showsPrec d (Showable f) = f d

さて、誰にも話さない場合、のインスタンスは、の引数でポリモーフィックであり、最大でShowインスタンスまで制約されたインスタンスShowableのみになります。エンドユーザーが他の拡張機能を使用してコードを積極的に破壊しようとしない限り、これは妥当な理由です。機能依存性および/または重複/決定不可能なインスタンスを追加することで、ある程度の問題が発生する可能性がありますが、意図を覆すものだけであり、クラッシュを引き起こす可能性はありません。Show (f Showable)a

これで、決定可能なインスタンスを作成できShowます。

data Free f a = Pure a | Free (f (Free f a))

instance (Functor f, Show (f Showable), Show a) => Show (Free f a) where
  showsPrec d (Pure a)  = showParen (d > 10) $ showString "Pure " . showsPrec 10 a
  showsPrec d (Free as) = showParen (d > 10) $ showString "Free " . showsPrec 10 (fmap showable as)

ここで示した実装は、の必要性を排除するものではありませんFlexibleContextsが、Haskell 98との互換性の必要性を本当に感じている場合は、いくつかの追加のクラスレイヤーを作成することで、それも排除できます。

私はこのトリックをいくつかのパッケージ(私のadパッケージを含む)で使用して、決定不可能なインスタンスの必要性を減らしています。

于 2012-06-04T02:39:33.873 に答える