モナド則3(結合律)を満たさない偽リストモナド

bind [] _ = []
bind [x] k = k x
bind xs@(x:_) k = case k x of
  [_] -> xs >>= k
  otherwise -> reverse $ xs >>= k

data MyList a = My { unMy :: [a] } deriving (Show,Eq)

instance Monad MyList where
  return x = My [x]
  (My xs) >>= k = My $ xs `bind` (unMy.k)


-- sample
m = My [1,5]
f x = My [x,2*x]
g x = My [x,x+1]

とすると

> (m >>= f) >>= g
My {unMy = [2,1,3,2,6,5,11,10]}

> m >>= (\x -> f x >>= g)
My {unMy = [5,6,10,11,1,2,2,3]}

のようにモナド則3(結合律)が成り立ちません。

結合律を満たさないと

do 
  x <- m
  y <- f x
  g y

の前半を別の関数にまとめた

do
  y <- h m
  g y

h m = do
  x <- m
  f x

と後半を別の関数にまとめた

do
  x <- m
  h x

h x = do
  y <- f x
  g y

では結果が違ってくるので一貫性をもってどの部分でも関数にまとめることができるという利便性が失われてしまいます。

追記(2009-07-09)

最初は otherwise -> drop 1 $ xs >>= k と書いていた drop 1 の部分を reverse に変更しそれにあわせて実行結果も修正。理由は reverse の方がかっこよさそうだから。