应用风格的动作之间的交流

问题描述

Haskell设计模式,编写此示例:

(+) <$> Nothing <*> Just 10 <*> Just 20

证明应用风格的动作之间的沟通有限。

问题是我无法在ghci中编译此示例,但出现错误:

<interactive>:28:1: error:
    • Non type-variable argument in the constraint: Num (a -> b)
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall a b. (Num (a -> b),Num a) => Maybe b

解决方法

该示例是错误的。其中任何一项工作:

Prelude> (+) <$> Nothing <*> Just 10
Nothing
Prelude> (+) <$> Just 10 <*> Just 20
Just 30
Prelude> (+) <$> Just 20 <*> Nothing
Nothing

但是给定的一个没有,因为(+)只有两个参数。

将其用作(+)<$>_<*>_<*>_意味着编译器将尝试推断其中(+)具有三个参数的类型。嗯,这并不是完全不可思议的,因为Haskell多参数函数实际上是一个参数的函数会产生另一个参数的函数,从而产生...
因此,“双参数函数” a -> a -> a 原则上,如果使用函数类型实例化a本身,则会有更多参数。说a ~ (Int -> Int),然后

(+) :: Num (Int -> Int) => (Int -> Int) -> (Int -> Int) -> Int -> Int
                           ┗━━━━━━━━━━┛    ┗━━━━━━━━━━┛    ┗━┛

Voilà,三个论点。问题是Int -> Int或更普遍的a->b不是数字类型,即Num (a -> b)不是可以满足的约束,尽管有人可以想到 >可以编写这样的实例。

请注意,有时Monoid (a,b) 约束是有意义的,GHC确实允许它们,但是您需要遵循建议并通过以下方式启用FlexibleContexts扩展名:将{-# LANGUAGE FlexibleContexts #-}放在源文件的顶部,或者将:set -XFlexibleContexts放在GHCi中。在您的示例中,这根本没有帮助。

要将(+)应用于任意数字或参数,可以将其折叠在列表上:

> :m +Data.List
> foldl1 (+) [0,10,20]
30

同样,您可以将应用提升格式(liftA2 (+) p q ≡ (+)<$>p<*>q)折叠在Maybe-numbers列表上:

> :m +Control.Applicative
> foldl1 (liftA2(+)) [Nothing,Just 10,Just 20]
Nothing
> foldl1 (liftA2(+)) [Just 0,Just 20]
Just 30

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...