将混合类型(可能是 Applicative)类型的参数应用于函数的最佳方法

Aiu*_*iia 4 haskell applicative

我对 Haskell 和函数式编程还很陌生,最近我一直在学习 Functors、Applicatives 和 Monads。虽然我似乎了解基础知识,但当某些参数的类型更改为 Applicative 时,我很难找出应用函数参数的最佳/最惯用的方法。考虑以下简单代码:

myfun :: Int -> Int -> Int -> Int
myfun a b c = a + b + c             -- lets pretend this does something more complicated

a = 5
b = 10
c = 20

result = myfun a b c
Run Code Online (Sandbox Code Playgroud)

使用myfun计算结果是相当简单的。但是,由于我们的要求改变,我们的投入abc可能会改成即Maybe Int[Int]甚则Int。我们仍然可以myfun通过执行以下操作之一来使用我们的未修改:

result = myfun <$> a <*> b <*> c   -- either like this
result = liftA3 myfun a b c        -- or like that
Run Code Online (Sandbox Code Playgroud)

然而,在实际的参数ab并且c可能并不总是落得相同应用型内,因而这两种方法上面提到的是行不通的。在myfun不修改它的情况下仍然使该功能正常工作的最佳方法是什么?考虑a,b和的以下场景c

  • 有些是Int,有些是Maybe Int(申请的结果是Maybe Int
  • 有些是Maybe Int,有些是Either String Int(结果可能是Maybe IntEither String Int,如果有任何参数是Nothing或,则具有短路计算的语义Left
  • 有些是[Int],有些是Maybe Int(结果应该是Maybe [Int],其语义是计算所有可能的组合,就好像所有参数都是[Int],然后将其包装在 a 中Just,除非 Maybies 是Nothing,在这种情况下我们短路到Nothing

非常感谢任何见解!

Mar*_*ann 5

这取决于你想要发生什么。可能没有任何通用的方法来组合不同的 monad。一般来说,当你真正需要组合不同的 monad 时,你经常(总是?)使用 monad 转换器,但通常有更简单的解决方案。您提到的特定组合就是这种情况。

在所有这些特定情况下,您可以将一个 monad 转换为另一个。在下面,我将给出一些可以做到这一点的方法的例子。

其中一些示例使用来自 的函数Data.Maybe,所以我将从:

import Data.Maybe
Run Code Online (Sandbox Code Playgroud)

它在第一个示例中不是必需的,但在第二个和第三个示例中是必需的。

一些Int,一些Maybe Int

如果您有IntMaybe Int值的组合,则解决方案很简单。只需将Int值提升到Maybe Int. 您可以为此使用Justpure。这是一个使用示例pure

a1 = 5
b1 = Just 10
c1 = 20

result1 :: Maybe Int
result1 = myfun <$> pure a1 <*> b1 <*> pure c1
Run Code Online (Sandbox Code Playgroud)

结果是Just 35

一些Maybe Int,一些Either String Int

您可以通过将一个 monad 转换为另一个来重复这个技巧。如果您对案例有用,则可以将Maybe Int值转换为Either String Int值。您还可以通过丢弃值将值转换为值。StringNothingEither String IntMaybe IntString

这是一个转换Maybe Int为的示例Either String Int

a2 = Just 5
b2 = Right 10
c2 = Left "Boo!"

result2 :: Either String Int
result2 = myfun <$> maybe (Left "No value") Right a2 <*> b2 <*> c2
Run Code Online (Sandbox Code Playgroud)

此组合使用maybe来自的函数Data.Maybe。结果是Left "Boo!"

一些[Int],一些Maybe Int

你可以很容易地Maybe Int变成[Int]使用maybeToList

a3 = [5, 10]
b3 = Nothing
c3 = Just 20

result3 :: [Int]
result3 = myfun <$> a3 <*> maybeToList b3 <*> maybeToList c3
Run Code Online (Sandbox Code Playgroud)

这样做的结果是[]因为Nothing转换为[],这就是Applicative列表的工作方式。这可能不是你想要的,但我希望这些例子能激励你想出你喜欢的作品。