应用中的纯定义问题

reb*_*bit 3 haskell applicative

我是Haskell的初学者,我必须解决工作表问题,而这次我真的很困。救命!:))

我必须计算从functor到monad的某个monad的实例,我无法在Applicative实例中算出纯函数。我不想发布程序的所有代码,但我认为以下应该可以说明问题:

这是给定的代码,无法更改:

class (Semigroup a, Monoid a) => Log a where
    logMsg :: String -> a

newtype Logger l a = Logger (a,l)
    deriving Show

logMsgM :: Log l => String -> Logger l ()
logMsgM s = Logger ((), logMsg s)
Run Code Online (Sandbox Code Playgroud)

这些是我正在处理的实例:

instance (Log l) => Functor (Logger l) where 
    fmap g (Logger (a, l)) = Logger ((g a), l)


instance (Log l) => Applicative (Logger l) where 
    pure ???????????????????
    (<*>) (Logger (g,l)) (Logger (a,_)) = Logger ((g a), l)

instance (Log l) => Monad (Logger l) where 
    return                                              = pure
    (>>=) (Logger (a,l)) g                              = (g a)
    (>>)  x y                                           = x >>= \_ -> y
Run Code Online (Sandbox Code Playgroud)

纯粹的我被困住了。pure = Logger会产生无限类型错误a〜(a,l),并且所有使用输入参数进行调整的尝试都将以未知变量错误或带有尾随零等类型变量的奇怪类型错误结束。我做了很多尝试,很难以更明智的方式发布错误消息。我不了解发生了什么。这是基于入门讲座的,所以我了解基本概念。我只是无法使用函数声明(我认为...)正确处理此新类型定义,尤其是将两个参数归为一个(对)的情况。我确实理解(或更恰当的措辞:“我可以遵循”)带有类型定义或新类型的案例的典型示例,例如,也许,或者,或者其他在右侧具有相同数量或更多参数的案例。然而,

顺便说一句,编写pure = return时,整个代码都会编译,但是程序会产生堆栈溢出(微笑)。我认为这也就不足为奇了,因为return = puer和pure = return可以很好地编译,但是没有任何意义,对吧!

感谢您的帮助:)

bra*_*drn 6

Logger是更普遍称为Writermonad的类型。这个想法是,如果您有一个Logger l a,且l为a Semigroup,那么如果您先运行a Logger l a,然后运行另一个Logger l b,则结果将使两个ls彼此相邻(即,使用该Monoid操作进行串联)。那是:

Logger (1,"test1") >> Logger (2,"test2")   ==   Logger (2,"test1" <> "test2")
Run Code Online (Sandbox Code Playgroud)

鉴于此,pure a将为Logger (a, something),其中something的值在连接时不起作用。但是现在来看一下typeclass声明:

class (Semigroup a, Monoid a) => Log a where ...
instance (Log l) => Applicative (Logger l) where ...
Run Code Online (Sandbox Code Playgroud)

所以在Applicative (Logger l)l必须是一个Monoid,所以必须具有一个身份值mempty!这给了我们pure a = Logger (a, mempty),它只是返回a而不会影响日志。


但是,仍然存在问题。如果我们有Logger (a1,l1) >>= \x -> Logger (a2,l2)Logger (a1,l1) <*> Logger (a2,l2),我们想l1 <> l2将结果串联起来。但是您当前的实现无法做到这一点!因此,您需要更改它才能满足此属性。由于我不想为您解决整个工作表,因此我将其保留为练习;但是,如果您陷入困境,则可能需要查阅此答案顶部的链接。

  • 非常感谢您的解释,这确实很有帮助。同时,也感谢您对&gt;&gt; =的提示,目前我看不到,但会尝试自己解决。我总是尽量在没有帮助的情况下完成任务。这就是将概念与实践联系起来的方式,对吗?就像数学一样,您可能知道所有公理,句子以及任何东西,但是,如果没有实践,即使在正确和有意义地应用它们方面可能会严重失败。:) (2认同)