Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redefine list monad instance

I'd like to supply my own instance for the list monad. Unfortunately, the following causes a duplicate instance declaration error when compiling.

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

From the documentation, it seems like it's not possible to hide instance declarations when importing, and since the list monad instance is already declared in the prelude, I guess I can't get rid of the import itself either.

I figured that maybe I could at least rebind (>>=) and return so that I would be able to use do blocks using my own implementation since do blocks are supposedly just syntactic sugar for applications of (>>=) and (>>).

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

Unfortunately, it seems like do blocks get their (>>=) from somewhere else, because it's still using the (>>=) of the default list monad instance.

Is there any way to make my implementations of (>>=) and return an instance of list monad, or at least a way to use them with do blocks?

like image 993
Jules Avatar asked Dec 26 '22 21:12

Jules


1 Answers

You cannot define another Monad instance for lists, in some circumstances you can define a newtype to work around that, but you'd have to manually lift all list functions to the newtype to use them.

To just use your own (>>=) and return in do-blocks, you can use a language extension with 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)

resulting in

$ 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]

With NoImplicitPrelude, desugaring of do-notation uses whatever (>>=) and return are in scope.

like image 113
Daniel Fischer Avatar answered Jan 11 '23 08:01

Daniel Fischer