do 表記は「base:GHC.Base.Monad」に固有のものですか?
質問
スタンダードという考え方は、 Monad
クラスに欠陥があるため、実際には拡張する必要がある Functor
または Pointed
浮遊している。
私はそれが正しいことであるとは必ずしも主張しませんが、ある人がそれを行おうとしていたと仮定してください。
import Prelude hiding (Monad(..))
class Functor m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
join = (>>= id)
(>>=) :: m a -> (a -> m b) -> m b
a >>= t = join (fmap t a)
(>>) :: m a -> m b -> m b
a >> b = a >>= const b
ここまではうまくいきましたが、do 記法を使用しようとすると次のようになります。
whileM :: Monad m => m Bool -> m ()
whileM iteration = do
done <- iteration
if done
then return ()
else whileM iteration
コンパイラは次のように不平を言います。
Could not deduce (base:GHC.Base.Monad m) from the context (Monad m)
質問:
do 記法は次の場合にのみ機能しますか base:GHC.Base.Monad
?代替手段で動作させる方法はありますか Monad
クラス?
追加のコンテキスト:
本当にやりたいのは交換です base:Control.Arrow.Arrow
「一般化された」 Arrow
クラス:
{-# LANGUAGE TypeFamilies #-}
class Category a => Arrow a where
type Pair a :: * -> * -> *
arr :: (b -> c) -> a b c
first :: a b c -> a (Pair a b d) (Pair a c d)
second :: a b c -> a (Pair a d b) (Pair a d c)
(***) :: a b c -> a b' c' -> a (Pair a b b') (Pair a c c')
(&&&) :: a b c -> a b c' -> a b (Pair a c c')
そして、 Arrow
のプロシージャ表記と私の Arrow
class ですが、上記の do 表記の例のように失敗します。 Monad
.
ほとんど使います Either
私のペア型コンストラクターとしてではなく、 (,)
現在と同様の型コンストラクター Arrow
クラス。これにより、私のおもちゃの RTS ゲームのコードを作成できるようになるかもしれません (cabal install DefendTheKind
)ずっときれいです。
解決
を使用する必要があります。 NoImplicitPrelude 拡張機能 完全な再バインド可能な構文については、 do
そして proc
. 。その場合、特に以下のものが得られます。
「Do」表記は、スコープ内にある関数 (>>=)、(>>)、fail を使用して変換されます (Prelude バージョンではありません)。リスト内包表記、mdo (セクション7.3.6「再帰的な do 表記」)、および並列配列内包表記は影響を受けません。
否定、等価、リテラル値などの処理を微調整することもできます。コードを難読化する素晴らしい方法です。
追記-- 再バインドする場合は、 do
構文、 sigfpe が「パラメータ化モナド」と呼ぶもの とても楽しいです。同じアイデアは以下でも利用できます category-extras
下 Control.Monad.Indexed. 。そして、はい、型署名が大幅に異なるにもかかわらず、再バインド可能な構文で動作します。