为什么不在 Applicative 上定义所有函数?

lun*_*nuy 0 haskell applicative

internalAnd :: Bool -> Bool -> Bool
internalAnd True True = True
internalAnd _ _ = False

(&&) :: Applicative m => m Bool -> m Bool -> m Bool
(&&) = liftA2 internalAnd


-- Usage
greaterThan x = (x <)
lessThan x = (x >)

validateAge = greaterThan 0 && lessThan 120  -- It's really useful with combinators.
Run Code Online (Sandbox Code Playgroud)

Applicative我认为对于许多情况(例如创建组合器)定义所有函数很有用。而applicative是对适用性的抽象,对应于函数的能力,所以这样做似乎也不错。

定义所有函数的预期问题是什么Applicative

Nou*_*are 8

一个缺点是您现在不能再将它用于普通布尔值。所以,你必须写pure True && pure False而不是True && False. 如果你想得到结果,你就必须使用runIdentity :: Identity a -> a或类似的东西。

一个更微妙的问题是您提出的函数不太懒惰。通常,程序员预计&&会发生短路。False所以如果你写它仍然应该返回False && undefined,但是如果你写你的函数将会卡住pure False && undefined。实际上你想将它实现为一个 monad:

(&&) :: Monad m => m Bool -> m Bool -> m Bool
x && y = do
  x' <- x
  if x
    then y
    else pure False
Run Code Online (Sandbox Code Playgroud)

一个常见的替代方法是给它另一个名称,例如<&&>

  • 此外,[关于applicatives的原始论文](https://www.staff.city.ac.uk/~ross/papers/Applicative.pdf)讨论了一种称为*习语括号*的符号,用于自动提升任何函数。成语括号可以让您写成“⟦ x &amp;&amp; y ⟧”(或普通 ASCII 格式的“i[ x &amp;&amp; y ]i”:“i”代表“成语”),而不是写“liftA2 (&amp;&amp;) xy”。 (3认同)