哈斯克尔。 Num表达式中的函数

时间:2016-05-16 12:08:28

标签: function haskell

我开始学习Haskell。在学习教程时,我发现了以下示例,它允许在算术表达式中使用函数:

module FunNat where

    instance Num a => Num (t -> a) where
        (+) = fun2 (+)
        (*) = fun2 (*)
        (-) = fun2 (-)

        abs      = fun1 abs
        signum   = fun1 signum

        fromInteger = const . fromInteger

    fun1 :: (a -> b) -> ((t -> a) -> (t -> b))
    fun1 = (.)

    fun2 :: (a -> b -> c) -> ((t -> a) -> (t -> b) -> (t -> c))
    fun2 op a b = \t -> a t `op` b t

该示例有效。但我无法理解(+)函数如何转换为两个参数的函数。据我所知,每个(+)都替换为fun2 (+)。而fun2相当于一个参数\t -> a t 'op' b t的函数,但我们应该有两个参数的函数(类似(\t1 t2 -> (\x -> x ) t1 + (\x -> x) t2))。我认为这里应该应用Haskell类型的一些基本概念,但我不知道它们是什么。

编辑1

我知道fun2是三个参数的函数。我无法理解内部表达转换。我的推理方式如下:(+) 3 4 = (+) (\x->3) (\x->4) = fun2 (+) (\x->3) (\x->4) = \t -> (\x->3) t + (\x->4) t 这是什么?或者我在推理中哪里错了?可能有必要以另一种方式思考吗?

编辑2

我认为我已经对这个问题有了一些了解(谢谢大家!)。所以:

  1. 当我们写(+) 3 4时 - 在这种情况下,使用来自Num的简单操作,FunNat没有特殊功能。要使用(+)中的FunNat,必须撰写fun2 (+) 3 4fun2 (+) (\x -> 3) (\x -> 4)。但是这些表达式期望评估任何第三个参数;

  2. 要展示FunNat的具体功能,我们可以使用以下示例((*)-(+))(摘自教程)或其他形式 - (-) (*) (+)。两个表达式都有两个参数。在这种情况下,我们有:((*)-(+)) = fun2 (-) (*) (+) = \t -> (*) t - (+) t = \t -> (\t1 t2 -> t1 * t2) t - (\t1 t2 -> t1 + t2) t = (\t t2 -> t * t2) - (\t t2 -> t + t2) = \t t2 -> (t * t2) - (t + t2)。最后的表达式只需要Num。我希望所有这些都是正确的

  3. 正如教程中所解释的那样,但是我无法理解,使用(*)(+)作为期望{{1}的fun2参数的可能性基于以下内容(取自教程):(t->a) = t1 -> t2 -> a其中t1->a'。这里使用了curring。

  4. 因此,所有必要的事实都是表面上的,但我没有考虑类型推理的非平凡机制。

2 个答案:

答案 0 :(得分:1)

(+)的类型为Num a => a -> a -> a。由于您要为Num类型创建Num a => t -> a的实例,请考虑显式签名

(+) :: Num a => (t -> a) -> (t -> a) -> (t -> a)(1)

或等效(通过currying)

(+) :: Num a => (t -> a) -> (t -> a) -> t -> a(2)

这说的是:"如果你给我2个从Num a => a产生t的策略,我可以创建一个新策略来生成Num a => a使用t""

Num.(+)个实例a

我认为你感到困惑的部分是这个特定的(+)可以看作是2个参数的函数,它返回一个函数(1),或者一个函数的3个参数,它返回一个值(2) 。由于Haskell中的函数是咖喱的,所以这些都是一样的。

答案 1 :(得分:0)

在类型签名中,括号与右侧相关联,因此:

f :: a -> (b -> c -> d)

与:

相同
f :: a -> b -> c -> d

所以下面的表示是多余的:

fun2 :: (a -> b -> c) -> ((t -> a) -> (t -> b) -> (t -> c))
                         ^                                ^

并删除它们:

fun2 :: (a -> b -> c) -> (t -> a) -> (t -> b) -> (t -> c)
          arg1             arg2        arg3