Purescript 守卫失败并显示:未找到 Control.MonadZero.MonadZero 身份的类型 class 实例
Purescript guard fails with: No type class instance found for Control.MonadZero.MonadZero Identity
visitNode :: Castle -> State (Set Castle) Unit
visitNode c = do
s <- get
guard $ not (member c s)
modify \acc -> insert c s
我有一些简单的代码来访问由自定义数据类型表示的节点。我认为像 guard 这样的 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
None 其中帮助或编译,我很确定我误解了这里的问题。我如何在这种情况下使用 guard 或任何其他 monadic 检查?
编辑:这个答案解决了问题中直接指出的问题,例如:
guard
用法,MonadPlus
上下文和 newtype
推导。
我认为@Fyodor Soikin 的答案通过将 guard
替换为 when
解决了这个问题的本质,所以这个答案可以被视为补充 material.
我认为如果你尝试这样的事情:
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
个实例依赖于此。
现在让我们回头尝试解决您遇到的一些问题。
It gives me the error:
No type class instance was found for
Control.MonadZero.MonadZero Identity
此消息告诉我们 Identity
没有 MonadZero
实例。如果我们检查什么是 MonadZero
we are going to discover that it is a class which implicates that given type has also Monad
and Alternative
instance and which satisfies the Annihilation
law... Identity
has no Alternative
instance because it require that given type has a 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
我认为当我们只有一个构造函数 Identity ∷ ∀ a. a → Identity a
.
时,不可能为 empty
(其中 empty :: ∀ a. f a
)值找到任何好的候选者
例如,在 Maybe
的情况下,我们有 empty = Nothing
和 <|>
,此值总是给出 Nothing
。
Which I don't understand why MonadZero would not work in this context, but regardless, I attempted to derive the Identity for MonadZero with things like this:
newtype Identity a = Identity a
derive instance newtypeIdentity :: Newtype (Identity a) _
derive newtype instance monadZeroIdentity :: MonadZero Identity
当您使用新类型派生时,您是在告诉编译器您的 newtype
实例应该使用 "inner type" 实例作为实现。在这种情况下,您只有 a
类型参数,手头没有 "underlyning" 实例。
我认为如果你想使用这样的派生,你必须使用你想要使用的实例的具体类型。例如,这里我们为我们的类型 MaybeWrapper
派生 Functor
,它使用 Maybe
实例来提供适当的成员实现(在这种情况下为 map
):
newtype MaybeWrapper a = MaybeWrapper (Maybe a)
derive instance newtypeMaybeWrapper :: Newtype (MaybeWrapper a) _
derive newtype instance functorMaybeWrapper :: Functor MaybeWrapper
快乐的 PureScript 黑客!
这里你需要的是when
,而不是guard
。
guard
仅适用于有可能 not 产生结果的单子。这种 monad 的一个例子是 Maybe
,其中 guard
将在条件为假时产生 Nothing
。另一个示例是 Array
,其中 guard
会在条件为假时生成一个空数组。等等。
在你的例子中,你的 monad 总是 产生一个值,所以 guard
在那里真的无关紧要。
相反,如果我正确理解你的逻辑,你要做的是在条件为真时产生效果,而在条件为假时跳过产生效果。这可以通过 when
or its evil twin unless
:
来完成
visitNode c = do
s <- get
unless (member c s) $
modify \_-> insert c s
另请注意,您没有在 modify
下使用参数 acc
。我用下划线替换了它,但实际上,如果你不使用参数,你不需要 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
效果越差越好
visitNode :: Castle -> State (Set Castle) Unit
visitNode c = do
s <- get
guard $ not (member c s)
modify \acc -> insert c s
我有一些简单的代码来访问由自定义数据类型表示的节点。我认为像 guard 这样的 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
None 其中帮助或编译,我很确定我误解了这里的问题。我如何在这种情况下使用 guard 或任何其他 monadic 检查?
编辑:这个答案解决了问题中直接指出的问题,例如:
guard
用法,MonadPlus
上下文和 newtype
推导。
我认为@Fyodor Soikin 的答案通过将 guard
替换为 when
解决了这个问题的本质,所以这个答案可以被视为补充 material.
我认为如果你尝试这样的事情:
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
个实例依赖于此。
现在让我们回头尝试解决您遇到的一些问题。
It gives me the error:
No type class instance was found for Control.MonadZero.MonadZero Identity
此消息告诉我们 Identity
没有 MonadZero
实例。如果我们检查什么是 MonadZero
we are going to discover that it is a class which implicates that given type has also Monad
and Alternative
instance and which satisfies the Annihilation
law... Identity
has no Alternative
instance because it require that given type has a 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
我认为当我们只有一个构造函数 Identity ∷ ∀ a. a → Identity a
.
empty
(其中 empty :: ∀ a. f a
)值找到任何好的候选者
例如,在 Maybe
的情况下,我们有 empty = Nothing
和 <|>
,此值总是给出 Nothing
。
Which I don't understand why MonadZero would not work in this context, but regardless, I attempted to derive the Identity for MonadZero with things like this:
newtype Identity a = Identity a derive instance newtypeIdentity :: Newtype (Identity a) _ derive newtype instance monadZeroIdentity :: MonadZero Identity
当您使用新类型派生时,您是在告诉编译器您的 newtype
实例应该使用 "inner type" 实例作为实现。在这种情况下,您只有 a
类型参数,手头没有 "underlyning" 实例。
我认为如果你想使用这样的派生,你必须使用你想要使用的实例的具体类型。例如,这里我们为我们的类型 MaybeWrapper
派生 Functor
,它使用 Maybe
实例来提供适当的成员实现(在这种情况下为 map
):
newtype MaybeWrapper a = MaybeWrapper (Maybe a)
derive instance newtypeMaybeWrapper :: Newtype (MaybeWrapper a) _
derive newtype instance functorMaybeWrapper :: Functor MaybeWrapper
快乐的 PureScript 黑客!
这里你需要的是when
,而不是guard
。
guard
仅适用于有可能 not 产生结果的单子。这种 monad 的一个例子是 Maybe
,其中 guard
将在条件为假时产生 Nothing
。另一个示例是 Array
,其中 guard
会在条件为假时生成一个空数组。等等。
在你的例子中,你的 monad 总是 产生一个值,所以 guard
在那里真的无关紧要。
相反,如果我正确理解你的逻辑,你要做的是在条件为真时产生效果,而在条件为假时跳过产生效果。这可以通过 when
or its evil twin unless
:
visitNode c = do
s <- get
unless (member c s) $
modify \_-> insert c s
另请注意,您没有在 modify
下使用参数 acc
。我用下划线替换了它,但实际上,如果你不使用参数,你不需要 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
效果越差越好