我是Haskell的新手。我正在学习monads。
data Container a = Container a deriving Show
x = Container 1 :: Container Int
plusOne :: Container Int -> Container Int
plusOne (Container x) = Container (x+1)
有没有办法解除plusOne
申请Container (IO Int)
?
或者我应该定义一个新功能,例如:
plusOne' :: Container (IO Int) -> Container (IO Int)
plusOne' (Container x) = Container (liftM (+1) x)
全部谢谢:-) 那有没有办法避免重新定义plusOne?
因为我构建程序,所以首先用非monadic类型的容器构建程序(正常值如:Container Int ..etc), 我用指定的值测试函数(容器10 ..)。
然后我尝试将这些程序应用于随机或生成的值。 这是我用其他语言编程的基本方法(比如Lisp,Python ..)
所以当我想尝试将这些函数应用于monadic-value容器时,我不想重新定义函数。
这种方法不适用于Haskell编程吗?我应该改变我的思维模式吗? 或者我误解了Haskell?
答案 0 :(得分:7)
看起来Container
应该是Functor的实例:
instance Functor Container where
fmap f (Container a) = Container (f a)
然后
plusOne = fmap (+1)
和
plusOne' = fmap $ liftM (+1)
然而,现在我发现我可能误解了这个问题......
答案 1 :(得分:6)
首先,看起来您实际上已经重新定义了the Identity
monad。
如果您在此处使用包含其他仿函数的仿函数,则您不希望自己完成所有记账,以确保您拥有正确数量的fmap
等等。这就是monad transformers进来的地方。
The MTL library(应该随Haskell平台一起提供)已经为你完成了所有艰苦的工作,你只需要做一些(好的,很多)管道工作,让你自己的类型与所有人一起工作现有的monad变形金刚。一旦你完成了这一点,你的Container
应该是一个好公民,作为任何monad堆栈的成员。
当然,通常的警告适用:monad变形金刚强大且难以理解。有一半你认为你需要它们,你并不是真的 - 所以要确保你使用正确的方法来解决你的问题。