繁体   English   中英

在haskell中创建monad

[英]Creating monads in haskell

我想创建自己的monad。 这就是我写的:

data LeafConType a = LeafCon (a,Int,Int)

instance Monad (LeafConType ) where
return = LeafCon 
lc@(LeafCon (t,i,n)) >>= f = if i>=n
                                then lc
                                else f (t,i,n)

但这不行。 Ghc说:

leafcon.hs:26:1:
    Occurs check: cannot construct the infinite type: a = (a, Int, Int)
    When generalising the type(s) for `return'
    In the instance declaration for `Monad LeafConType'

leafcon.hs:27:1:
    Occurs check: cannot construct the infinite type: a = (a, Int, Int)
    When generalising the type(s) for `>>='
    In the instance declaration for `Monad LeafConType'

那有什么不对吗?


当我低于n时,我想做计算。 n应该是常数我还不知道如何做到这一点。 它应该是State和Maybe的混合体。 如果您有任何建议,请随时与我分享:P

关于return

Prelude> :t return
return :: (Monad m) => a -> m a 

因此, return需要类型的参数a ,并返回一个类型的东西ma 在这种情况下, mLeafConType ,因此返回LeafConType a

现在假设我们传递了True 然后a = Bool ,所以返回类型必须是LeafConType Bool 但是,您定义:

return = LeafCon

所以, return True成为LeafCon True 但是这是不允许的,因为LeafConType的类型定义表明了这一点

data LeafConType a = LeafCon (a, Int, Int)

因此,对于LeafConType Bool的参数LeafCon必须有类型(Bool, Int, Int)而不仅仅是Bool 这就是编译错误的含义: a不能与(a, Int, Int) 你说:

i低于n时, i想做计算。

这意味着您将需要in一些默认值,否则将无法定义return 如果默认情况下它们都为零,那么您可以定义:

return a = LeafCon (a, 0, 0)

关于(>>=)

Prelude> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b

现在看看你的实现(略有不同的表示法,相同的想法):

lc@(LeafCon (t, i, n)) >>= f | i >= n    = lc 
                             | otherwise = f t

我们在这里看到的是,当i >= n时返回lc lc的类型为LeafConType a ,而f是一个函数,可以为任何 b返回LeafConType b类型的值。 结果可能是b不等于a ,因此这些类型不匹配。 总之,你真的要问自己一个问题:

这种类型的计算是否可以表示为monad?

您为>>=return指定的函数不满足Monad所需的类型:

return :: a -> LeafConType a

鉴于声明

return = LeafCon

你赋予函数不兼容的类型

return :: (a, Int, Int) -> LeafConType a

因此, return 42这样的陈述在你的monad中是不可能的。

我不明白你的monad应该做什么。 首先来看看简单,有效的monad!

instance Monad [] where
    (>>=) = concatMap
    return a = [a]

instance Monad Maybe where
    return = Just
    (Just x) >>= f = f x
    Nothing >>= f = Nothing

从您对monad要做的事情的描述来看,我认为你想要的东西有点像这样:

data LeafConType a = LeafCon { runLeafCon' :: Int -> Int -> (Maybe a, Int, Int) }

runLeafCon :: Int -> Int -> LeafConType a -> Maybe a
runLeafCon i n lc = let (t, _, _) = runLeafCon' lc i n in t

getI :: LeafConType Int
getI = LeafCon $ \i n -> (Just i, i, n)

getN :: LeafConType Int
getN = LeafCon $ \i n -> (Just n, i, n)

setI :: Int -> LeafConType ()
setI i = LeafCon $ \_ n -> (Just (), i, n)

setN :: Int -> LeafConType ()
setN n = LeafCon $ \i _ -> (Just (), i, n)

instance Monad LeafConType where
    return t = LeafCon $ \i n -> if (i < n) 
                                 then (Just t, i, n) 
                                 else (Nothing, i, n)

    (LeafCon k) >>= f = 
        LeafCon $ \i n -> 
            let (t, i', n') = k i n
            in case t of
                 Nothing -> (Nothing, i', n')
                 (Just t') -> if (i' < n')
                              then runLeafCon' (f t') i' n'
                              else (Nothing, i, n)


example :: Int -> LeafConType ((), Int)
example x = do 
  i <- getI
  m <- setI (i + x)
  return (m, i + x)

一些例子:

*Main> runLeafCon 2 10 $ example 4
Just ((),6)
*Main> runLeafCon 2 10 $ example 8
Nothing
*Main> runLeafCon 2 10 $ example 7
Just ((),9)

我很快把它扔在一起,它相当丑陋,而且我没有检查它是否符合任何Monad定律,所以使用你的危险! :)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM