visitNode :: Castle -> State (Set Castle) Unit
visitNode c = do
s <- get
guard $ not (member c s)
modify \acc -> insert c s
我有一些简单的代码可以访问由自定义数据类型表示的节点。我认为MonadZero的控制功能(如后卫)应该在所有monad结构(例如State)中都起作用。它给了我错误:
No type class instance was found for
Control.MonadZero.MonadZero Identity
我不明白为什么MonadZero在这种情况下不起作用,但是无论如何,我试图通过以下方式得出MonadZero的身份:
newtype Identity a = Identity a
derive instance newtypeIdentity :: Newtype (Identity a) _
derive newtype instance monadZeroIdentity :: MonadZero Identity
它们都没有帮助或编译,我敢肯定我会误解这里的问题。在这种情况下,我该如何使用警卫检查或其他任何单子检查?
答案 0 :(得分:1)
这里您需要的是when
,而不是guard
。
guard
仅适用于可能不产生结果的单子。这种单子的一个示例是Maybe
,其中,当条件为false时,guard
将产生Nothing
。另一个示例为Array
,其中,条件为false时,guard
将产生一个空数组。依此类推。
在您的情况下,您的monad总是 产生一个值,所以guard
在那里确实无关紧要。
相反,如果我正确理解了您的逻辑,那么您想要做的就是在条件为真时产生效果,而在条件为假时跳过产生结果。这可以通过when
或其邪恶的孪生兄弟unless
完成:
visitNode c = do
s <- get
unless (member c s) $
modify \_-> insert c s
还要注意,您没有使用acc
下的参数modify
。我已将其替换为下划线,但实际上,如果您不使用该参数,则不需要modify
,就不需要put
:
visitNode c = do
s <- get
unless (member c s) $
put (insert c s)
但是接下来要注意的是get
的模式,然后是put
的模式,正是modify
的目的。因此,在您的情况下,看看get
和put
之间没有任何影响,我实际上将所有逻辑放在modify
本身内:
visitNode c = modify \s ->
if member c s
then insert c s
else s
效果越差越好。
答案 1 :(得分:0)
编辑:此答案解决了直接在问题中指出的问题,例如:
guard
的用法,MonadPlus
上下文和newtype
的派生。
我认为@Fyodor Soikin答案通过将guard
替换为when
来解决了这个问题的本质,因此该答案可以被视为补充材料。
我认为,如果您尝试以下操作:
visitNode :: Castle -> StateT (Set Castle) Maybe Unit
visitNode c = do
s <- get
guard $ not (member c s)
modify \acc -> insert c s
它应该工作,因为Maybe
有MonadZero
实例,而StateT
实例依赖于此。
现在让我们回去尝试解决您遇到的一些问题。
它给了我错误:
No type class instance was found for Control.MonadZero.MonadZero Identity
此消息告诉我们Identity
没有MonadZero
实例。如果检查什么是MonadZero
,我们将发现它是一个类,它暗示给定类型也具有Monad
和Alternative
实例,并且满足Annihilation
律... Identity
没有Alternative
实例,因为它要求给定类型具有Plus
实例:
The Plus type class extends the Alt type class with a value that should be the left and right identity for (<|>)
(...)
Members:
empty :: forall a. f a
我认为,当我们只有一个构造函数empty
时,就不可能为empty :: ∀ a. f a
(其中Identity ∷ ∀ a. a → Identity a
)的值找到任何合适的候选人。
例如,在Maybe
的情况下,我们有empty = Nothing
和<|>
,此值始终为Nothing
。
我不明白为什么MonadZero在这种情况下不起作用,但是无论如何,我试图通过以下方式得出MonadZero的身份:
newtype Identity a = Identity a derive instance newtypeIdentity :: Newtype (Identity a) _ derive newtype instance monadZeroIdentity :: MonadZero Identity
使用新类型派生时,您是在告诉编译器newtype
的实例应使用“内部类型”实例作为实现。在这种情况下,您只有a
类型的参数,并且手边没有“底层”实例。
我认为,如果要使用这样的派生,则必须使用要使用的实例的具体类型。例如,在这里我们为类型Functor
导出MaybeWrapper
,该类型使用Maybe
实例提供适当的成员实现(在这种情况下为map
):
newtype MaybeWrapper a = MaybeWrapper (Maybe a)
derive instance newtypeMaybeWrapper :: Newtype (MaybeWrapper a) _
derive newtype instance functorMaybeWrapper :: Functor MaybeWrapper
快乐的PureScript黑客攻击!