Haskell检查monad中是否存在值

时间:2015-10-20 07:07:03

标签: haskell

我想知道monad的广义列表中是否存在null的等价物或其他内容。目前我正试图用== mzero找到错误的值。但是这种检查会引发误报,因为mzero /= Left "foo"适用。

是否有一种优雅的方式来表达标准库中我想要的东西?

4 个答案:

答案 0 :(得分:12)

Monad类型类没有捕获概念“包含值”。毕竟,Monad只能为您提供一些序列(>>=)动作(绑定前一个结果)。 MonadPlus为您提供了一种使用mzero“快捷”计算的方法(查看法律和mplus)。

然而,能够包含一个或多个值通常是能够将所有这些值一起折叠成某些东西的。实际上,Data.Foldable包含一个方便地也称为null的函数:

> import qualified Data.Foldable as F
> 
> showAndTell :: (Show (t a), Foldable t) => t a -> IO ()
> showAndTell k =
>   putStrLn $ "  F.null (" ++ show k ++ ") is " ++ show (F.null k)

> main = do
>   putStrLn "Using F.null on 'empty' things:"
>   showAndTell $ (Left "Error" :: Either String Int)
>   showAndTell $ (Nothing :: Maybe Integer)
>   showAndTell $ ([]      :: [Double])
> 
>   putStrLn ""
>   putStrLn "Using F.null on 'filled' things:"
>   showAndTell $ (Right 123 :: Either String Integer)
>   showAndTell $ (Just  123 :: Maybe Integer)
>   showAndTell $ ([1,2,3] :: [Int])

结果:

Using F.null on 'empty' things:
  F.null (Left "Error") is True
  F.null (Nothing) is True
  F.null ([]) is True

Using F.null on 'filled' things:
  F.null (Right 123) is False
  F.null (Just 123) is False
  F.null ([1,2,3]) is False

所以你要找的是Foldable的一部分,而不是Monad。这仅适用于GHC 7.10或更高版本,因为基础4.8.0.0中引入了Data.Foldable.null。如果您遇到旧版本的GHC,可以使用

> isEmpty :: F.Foldable t => t a -> Bool
> isEmpty = F.foldr (\_ _ -> False) True

答案 1 :(得分:5)

我不能当场记住任何适用于所有monad MaybeEither eMaybeT mExceptT e m的简单函数,它们是我能想到的主要单子其中有“错误的价值观”。

自GHC 7.10起,null实际上已被推广(至Foldable),因此它适用于前两个。

对于最后三个(Either e适用于这两种方法)及其转换版本,您可以使用catchError函数。

(虽然最后两个 Foldable个实例,但他们的null做错了。)

答案 2 :(得分:5)

绝对不是来自monad之外。如果您正在搜索nonEmpty :: MonadPlus m => m a -> Bool之类的内容,那么就不可能了。

您需要实际运行monadic计算,以确定它是否为#34;空白"。但是monad可能需要某种输入来运行(例如State甚至只是Reader之类的东西),并且在IO的极端情况下你不能运行monad在外面。现在这些例子并不是MonadPlus在他们自己的AFAICR上,而是以失败的方式对其进行补充(例如MaybeT),突然之间明确定义了对他们来说意味着什么? #34;空",但仍然适用相同的限制。由于一个未知的monad可能是其中之一,你无法获得任何信息。

可能的签名可能是nonEmpty :: MonadPlus m => m a -> m Bool(虽然我不确定这是否也有合理的实施)。但我并不认为这是你所追求的,因为它并没有真正概括null;您最终要为{(1}}或[False]退出列表(或者甚至可能[True]使用与输入相同数量的元素),这有点奇怪。

我认为monad是错误的"概括轴" [True, True, True, ...];你想要一个比null更好地表征容器的抽象(许多monads 容器,但是很多其他东西都是非常不同的,所以适用于任意monad的代码可以&# 39;假设容器般的属性)。像GHC-7.10中所发生的那样推广到Monad似乎是个不错的选择。你可以创建一个Foladable类型的类,它比CanBeEmpty承认更多的东西;我不知道这样的事情已经存在了。

答案 3 :(得分:2)

惯用的事情不是试图直接检测零,而是在零的情况下提供你想要的行为。

这是mplus或等效(在最近的前奏曲中)<|>所做的事情;它链接一个动作,以便在第一个动作失败的情况下运行。这与catchError支持的Monad上的catchError相同。它类似于shell或perl编程中的常用习惯用法foo || bar意味着运行foo然后在foo失败时运行bar。

请注意列表monad,它将运行所有选项,因为这是列表monad的设计工作方式,建模“多种可能性”。

我经常在<|>MaybeT上使用EitherT来模拟左偏选择,即“依次尝试所有这些替代方案直到成功”。

请注意,对<|>使用EitherT会丢弃错误消息(因为它会将失败的计算变为后续计算);如果您想要保存错误消息并以某种方式处理它,那么再次,catchError您想要。