我对此代码有一个问题:
append (first, second) f = (first ++ fst(f second), snd(f second))
^^^^^^^^^^^^^ ^^^^^^^^^^^^^
我不知道如何调用此功能,因为我不了解如何正确匹配^
标记的功能。在我看来,我需要一个返回元组的函数,因为函数fst需要这个。
答案 0 :(得分:6)
如果用显式模式匹配和共享重写一下你的表达式,事情会变得更加清晰:
append :: ([w], a) -> (a -> ([w], b)) -> ([w], b)
append (w, a) f = let (w', b) = f a
in (w ++ w', b)
因此,您使用列表和值获取元组,应用生成另一个列表的函数。该列表将附加到原始列表中,该值将替换元组中的前一个列表。
似乎你重新发明了((,) w)
monad又名作家monad!
查看>>=
(绑定)的类型,它将一个函数应用于生成另一个monadic值的momadic值:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
现在,如果您将m
替换为((,) w)
(或(w,)
,如果类型中允许使用元组部分的表示法),则m a
成为(w, a)
,你得到:
bindSpecialized :: (w, a) -> (a -> (w, b)) -> (w, b)
但是如果我们有办法合并((,) w)
,w
只能用作monad。您通过列表和++
实现了这一目标。更通用的方法是将类型类Monoid
用于具有关联操作和标识元素的类型。
由于某些原因,((,) w)
不是前奏中定义的monad,建议使用newtype:
newtype Writer w a = Writer { runWriter :: (w, a) }
instance Functor (Writer w) where
fmap f (Writer (w, a)) = Writer (w, f a)
instance Monoid w => Monad (Writer w) where
return a = Writer (mempty, a)
(Writer (w, a)) >>= f = let Writer (w', b) = f a
in Writer (w <> w', b)
tell :: Monoid w => w -> Writer w ()
tell w = Writer (w, ())
-- test == ("hello world", 3)
test :: (String, Int)
test = runWriter $ do
a <- test1
b <- test2
return $ a + b
where
test1 = tell "hello" >> return 1
test2 = tell " world" >> return 2
对于实际程序,您应该使用Writer
中已定义的{{1}}类型及其monad实例。