在守卫中使用单子布尔值? (模式卫士)
Using a monadic boolean value in a guard? (PatternGuard)
我刚刚发现了 PatternGuards 语言扩展,看起来非常不错。
我处于这样一种情况,我想对一个值进行模式匹配,对该值应用一元布尔函数,并且仅在结果为 False
时才执行某些操作。否则我想执行默认操作(可能不像下面列出的那么简单)。
这可以通过在进行模式匹配后使用 if
来实现,但我宁愿不复制默认操作的代码,或者将其移出到一个单独的函数中(即保留 fall通过守卫的行为)
有没有办法不用 if
?
{-# LANGUAGE GeneralizedNewtypeDeriving, PatternGuards #-}
import Control.Applicative
import Control.Monad.State
newtype MyM a = MyM (StateT Int (Either String) a)
deriving ( MonadState Int
, Monad, Applicative, Functor
)
--------------------------------------------------------------------------------
foo :: Int -> MyM Bool
foo = undefined
bar :: Either a Int -> MyM Int
bar (Right n)
| ok <- foo n, ok == False = return 42
bar _ = return 0
以上代码给出错误信息
Couldn't match expected type ‘MyM Bool’ with actual type ‘Bool’
In the second argument of ‘(==)’, namely ‘False’
In the expression: ok == False
你要求的是不可能的,而且有充分的理由。假设 foo
修改了状态,但守卫中的条件不匹配。您将如何处理这种状态修改?模式与值是分开的,因此匹配模式不会导致改变结果。
您确实需要在 RHS 中调用 foo
来决定如何处理其输出。
在某些情况下,如果 monad 是您可以匹配的数据类型,您可以执行以下操作
foo :: Int -> Maybe Bool
...
bar :: Either a Int -> MyM Int
bar (Right n)
| Just False <- foo n = ...
但这只是因为您可以直接匹配 monad 的值。
此外,在某些情况下,扩展 lambda-case and multi-way if-expressions 可以让您的生活更轻松。
我刚刚发现了 PatternGuards 语言扩展,看起来非常不错。
我处于这样一种情况,我想对一个值进行模式匹配,对该值应用一元布尔函数,并且仅在结果为 False
时才执行某些操作。否则我想执行默认操作(可能不像下面列出的那么简单)。
这可以通过在进行模式匹配后使用 if
来实现,但我宁愿不复制默认操作的代码,或者将其移出到一个单独的函数中(即保留 fall通过守卫的行为)
有没有办法不用 if
?
{-# LANGUAGE GeneralizedNewtypeDeriving, PatternGuards #-}
import Control.Applicative
import Control.Monad.State
newtype MyM a = MyM (StateT Int (Either String) a)
deriving ( MonadState Int
, Monad, Applicative, Functor
)
--------------------------------------------------------------------------------
foo :: Int -> MyM Bool
foo = undefined
bar :: Either a Int -> MyM Int
bar (Right n)
| ok <- foo n, ok == False = return 42
bar _ = return 0
以上代码给出错误信息
Couldn't match expected type ‘MyM Bool’ with actual type ‘Bool’
In the second argument of ‘(==)’, namely ‘False’
In the expression: ok == False
你要求的是不可能的,而且有充分的理由。假设 foo
修改了状态,但守卫中的条件不匹配。您将如何处理这种状态修改?模式与值是分开的,因此匹配模式不会导致改变结果。
您确实需要在 RHS 中调用 foo
来决定如何处理其输出。
在某些情况下,如果 monad 是您可以匹配的数据类型,您可以执行以下操作
foo :: Int -> Maybe Bool
...
bar :: Either a Int -> MyM Int
bar (Right n)
| Just False <- foo n = ...
但这只是因为您可以直接匹配 monad 的值。
此外,在某些情况下,扩展 lambda-case and multi-way if-expressions 可以让您的生活更轻松。