我刚刚发现了PatternGuards语言扩展,看起来非常好。
在我想要模式匹配值的情况下,对该值应用monadic布尔函数,并且仅在结果为False
时执行某些操作。否则我想执行默认操作(可能不像下面列出的那么简单)。
这可以通过在进行模式匹配后使用if
来实现,但我宁愿不复制默认操作的代码,也不要在单独的函数中将其移出(即保持行为下降)守卫)
有没有办法 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
答案 0 :(得分:3)
你所要求的是不可能的,而且有充分的理由。假设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扩展可以让您的生活更轻松。