4

リストモナドに独自のインスタンスを提供したいと思います。残念ながら、以下はコンパイル時にインスタンス宣言の重複エラーを引き起こします。

myReturn :: a -> [a]
myBind :: [a] -> (a -> [b]) -> [b]
instance Monad [] where
    return = myReturn
    (>>=) = myBind

ドキュメントを見ると、インポート時にインスタンス宣言を非表示にすることはできないようで、リストモナドのインスタンスはプレリュードですでに宣言されているため、インポート自体を取り除くこともできないと思います。

do ブロックはおそらくandのアプリケーションの構文糖衣にすぎないため、自分の実装を使用して do ブロックを使用できるように、少なくとも rebind (>>=)andできるのではないかと考えました。return(>>=)(>>)

let
    return = myReturn
    (>>=) = myBind
in
    do
        item1 <- list1
        item2 <- list2
        return (item1, item2)

残念ながら、デフォルトのリストモナドインスタンスを(>>=)まだ使用しているため、ブロックは別の場所から取得しているようです。(>>=)

リストモナドの実装(>>=)returnインスタンスを作成する方法、または少なくとも do ブロックでそれらを使用する方法はありますか?

4

2 に答える 2

6

リストの別のインスタンスを定義することはできませんMonad。状況によっては、それを回避するために newtype を定義できますが、すべてのリスト関数を手動で newtype に持ち上げて使用する必要があります。

独自の(>>=)doreturnブロックを使用するには、GHC で言語拡張を使用できます。

{-# LANGUAGE NoImplicitPrelude #-}
module ListMon where

import Prelude hiding ((>>=), return)

(>>=) :: [a] -> (a -> [b]) -> [b]
xs >>= foo = case xs of
               [] -> [undefined]
               [x] -> foo x ++ foo x
               ys -> take 10 $ concatMap foo $ take 5 ys

return :: a -> [a]
return x = [x,x,x]

someList :: [Int]
someList = do
    k <- [1 .. 4]
    h <- [2 .. 3]
    return (k + 12*h)

その結果

$ ghci ListMon
{- snip loading messages -}
[1 of 1] Compiling ListMon          ( ListMon.hs, interpreted )
Ok, modules loaded:
*ListMon> someList 
[25,25,25,37,37,37,26,26,26,38,38,38,27,27,27,39,39,39,28,28,28,40,40,40]

ではNoImplicitPrelude、do 表記の desugar は何でも使用し、範囲内にあります(>>=)return

于 2012-07-23T00:15:10.593 に答える
4

リストをnewtypeでラップできます

newtype MyList a = MyList { unMyList :: [a] }

このラップされた型のインスタンスを宣言します

instance Monad MyList where
    return = MyList . myReturn
    (MyList m) >>= f = MyList . myBind m f

次に、リストを newtype ラッパーでラップするだけですMyList(newtype は単なるシンタックス シュガーであるため、コンパイル時に削除されます)。

于 2012-07-23T00:11:57.587 に答える