我想为列表monad提供我自己的实例。不幸的是,以下内容在编译时会导致重复的实例声明错误。
myReturn :: a -> [a]
myBind :: [a] -> (a -> [b]) -> [b]
instance Monad [] where
return = myReturn
(>>=) = myBind
从文档中看,导入时隐藏实例声明似乎是不可能的,并且由于列表monad实例已在前奏中声明,我想我也无法摆脱导入本身。
我想也许我至少可以重新绑定(>>=)
和return
以便我可以使用自己的实现来使用do块,因为块应该只是{{{{ 1}}和(>>=)
。
(>>)
不幸的是,看起来阻止从其他地方获取let
return = myReturn
(>>=) = myBind
in
do
item1 <- list1
item2 <- list2
return (item1, item2)
,因为它仍在使用默认列表monad实例的(>>=)
。
有没有办法让我的(>>=)
和(>>=)
实现列表monad的实例,或者至少有一种方法可以将它们与do块一起使用?
答案 0 :(得分:6)
您无法为列表定义另一个Monad
实例,在某些情况下,您可以定义一个新类型来解决此问题,但您必须手动将所有列表函数提升为newtype才能使用它们。
要在do-blocks中使用您自己的(>>=)
和return
,您可以在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
时,des-notation会使用(>>=)
和return
范围内的任何内容。
答案 1 :(得分:4)
您可以将列表包装在newtype
中newtype MyList a = MyList { unMyList :: [a] }
并为此包装类型声明您的实例
instance Monad MyList where
return = MyList . myReturn
(MyList m) >>= f = MyList . myBind m f
现在只需将您的列表包装在newtype包装器MyList
中(newtypes只是语法糖,因此在编译时被删除)。