在警卫中使用monadic布尔值? (PatternGuard)

时间:2015-03-17 23:40:15

标签: haskell monads

我刚刚发现了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

1 个答案:

答案 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扩展可以让您的生活更轻松。