重新定义列表monad实例

Jul*_*les 3 monads haskell functional-programming typeclass

我想为列表monad提供我自己的实例.不幸的是,以下内容在编译时会导致重复的实例声明错误.

myReturn :: a -> [a]
myBind :: [a] -> (a -> [b]) -> [b]
instance Monad [] where
    return = myReturn
    (>>=) = myBind
Run Code Online (Sandbox Code Playgroud)

从文档来看,似乎不可能在导入时隐藏实例声明,并且由于列表monad实例已经在前奏中声明,我想我也无法摆脱导入本身.

我想也许我至少可以重新绑定(>>=),return以便我可以使用自己的实现来使用do块,因为块应该只是(>>=)和的应用程序的语法糖(>>).

let
    return = myReturn
    (>>=) = myBind
in
    do
        item1 <- list1
        item2 <- list2
        return (item1, item2)
Run Code Online (Sandbox Code Playgroud)

不幸的是,似乎块(>>=)从其他地方获取它们,因为它仍然使用(>>=)默认列表monad实例.

有没有办法让我的实现(>>=)returnlist monad的实例,或者至少是一种方法来使用do块?

Dan*_*her 6

您无法Monad为列表定义另一个实例,在某些情况下,您可以定义一个新类型来解决该问题,但您必须手动将所有列表函数提升为newtype才能使用它们.

要使用您自己的(>>=)return在do-blocks中,您可以使用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)
Run Code Online (Sandbox Code Playgroud)

导致

$ 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]
Run Code Online (Sandbox Code Playgroud)

随着NoImplicitPrelude,des-notation使用任何东西(>>=),return并在范围内.