【问题标题】:Is there a a predefined way to skip calculations that result in Nothing?是否有预定义的方法来跳过导致 Nothing 的计算?
【发布时间】:2016-10-27 15:13:32
【问题描述】:

我有这三个功能

a :: Int -> Maybe Int
a i = if i < 100 then Just i else Nothing

b :: Int -> Maybe Int
b i = if i < 50 then Just i else Nothing

c :: Int -> Maybe Int
c i = if i > 0 then Just i else Nothing

我想将它们链接在一起,以便当一个函数的结果导致 Nothing 时,返回该函数的输入。

我可以用这个功能实现:

import Data.Maybe (fromMaybe)

e :: Int -> [Int -> Maybe Int] -> Int
e i [] = i
e i (f:fs) = e (fromMaybe i $ f i) fs

-

*Main> e 75 [a,b,c]
75

在基础库中是否存在表现出这种行为的现有函数、Monad 实例或其他方式?

【问题讨论】:

  • 应该清楚,一般情况下不能这样做,因为输入和输出类型可能不同。您可以编写(a -&gt; Maybe a) -&gt; a -&gt; a 类型的函数,但不能编写(a -&gt; Maybe b) -&gt; a -&gt; b
  • 我首先像你一样使用fromMaybe[Int -&gt; Maybe Int] 变成[Int -&gt; Int]。之后,我将组成 endos 列表。
  • foldr1 (&gt;=&gt;) [a, b, c]
  • @AlexanderVoidExRuchkin 这与\i -&gt; e i [a,b,c] 的语义不同(其中e 在上面的问题中定义)。
  • e = fromMaybe 75 . foldr1 (&gt;=&gt;) [a,b,c],不过。

标签: haskell monads maybe


【解决方案1】:

扩展我上面的评论——这种方法与 OP 发布的代码没有太大区别。

我们首先定义如何将函数a -&gt; Maybe a 转换为a -&gt; a,用输入替换Nothing

totalize :: (a -> Maybe a) -> (a -> a)
totalize f x = fromMaybe x (f x)

然后,我们利用上述内容:我们将每个函数设为“total”(意思是 no-Nothings),将其包装为 Endo,然后我们组成自同态列表(mconcatEndo幺半群)。

e :: [a -> Maybe a] -> a -> a
e = appEndo . mconcat . map (Endo . totalize)

甚至(如下所示)

e :: Foldable t => t (a -> Maybe a) -> a -> a
e = appEndo . foldMap (Endo . totalize)

【讨论】:

  • e = appEndo . foldMap (Endo . totalize)?
  • 你也可以不用Endo抽象:compose = foldr (.) id; e = compose . map totalize
【解决方案2】:

好吧,您可以从a -&gt; Maybe a 创建一个a -&gt; a

repair :: (a -> Maybe a) -> a -> a
repair f x = fromMaybe x (f x)

之后,您可以将(.)repair 组合起来:

andThen :: (a -> Maybe a) -> (a -> Maybe a) -> a -> a
andThen f g = repair g . repair f

但是没有用于此的库函数,因为没有通用方法可以从 Monad 中获取值。

【讨论】:

    【解决方案3】:

    你在寻找可能的单子吗?

    *Main> let f x = a x >>= b >>= c >> return x
    *Main> f 1
    Just 1
    *Main> f 100
    Nothing
    *Main>
    

    如果结果是 Nothing 我们可以使用 fromMaybe(或者只是 maybeid,同样的事情)达到您想要的最终状态:

    *Main> let g x = maybe x id (f x)
    *Main> g 100
    100
    

    【讨论】:

    • 这与 OP 代码不同。 OP 代码,当a x 返回Nothing 时,将x 提供给b。一元链不这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-17
    • 1970-01-01
    • 2011-05-03
    • 2020-03-25
    • 1970-01-01
    相关资源
    最近更新 更多