Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 这是有效类型吗?我如何满足它?(由两个并矢函数组成)_Haskell_Composition - Fatal编程技术网

Haskell 这是有效类型吗?我如何满足它?(由两个并矢函数组成)

Haskell 这是有效类型吗?我如何满足它?(由两个并矢函数组成),haskell,composition,Haskell,Composition,我的问题很简单,作为haskell的初学者,我一直在思考类型、函数组合以及如何应用它们。我开始思考(+)(*)的结果可能是什么 现在很明显,这个问题的解决方案是打开ghci并找出答案。因此,我这样做并检查了类型: λ> :t ((*) . (+)) ((*) . (+)) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a 这种类型可能吗?我在努力理解它可能是什么或者它意味着什么 再次为这个简单化的问

我的问题很简单,作为haskell的初学者,我一直在思考类型、函数组合以及如何应用它们。我开始思考
(+)(*)
的结果可能是什么

现在很明显,这个问题的解决方案是打开ghci并找出答案。因此,我这样做并检查了类型:

λ> :t ((*) . (+))
((*) . (+)) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
这种类型可能吗?我在努力理解它可能是什么或者它意味着什么


再次为这个简单化的问题道歉,我尝试输入函数的所有内容都失败了。我只是想用并矢函数来发展函数合成的直觉。

不幸的是,GHC并没有给出一个很好的信息。这几乎肯定不是你想要的。默认情况下,
Num(a->a)
没有实例,实现一个实例可能对某些事情有用,但可能会导致非常不直观的运行时错误。即使在这种情况下,此函数也不太可能有用

让我们看看类型受限的
(*)
(+)
,以简化情况并避免增加类型类的复杂性:

(*!) :: Int -> Int -> Int
(*!) = (*)

(+!) :: Int -> Int -> Int
(+!) = (+)
现在当我们尝试

λ> :t (*!) . (+!)

<interactive>:1:8:
    Couldn't match type ‘Int -> Int’ with ‘Int’
    Expected type: Int -> Int
      Actual type: Int -> Int -> Int
    Probable cause: ‘(+!)’ is applied to too few arguments
    In the second argument of ‘(.)’, namely ‘(+!)’
    In the expression: (*!) . (+!)
(*!)
的左参数是一个函数,它与预期的
Int
类型不匹配

用两个参数的函数组合 为此,我们需要一个函数
(b->c)->(a1->a2->b)->a1->a2->c
。幸运的是,这正是
()
的含义

λ> :t ((.) . (.)) (*!) (+!)
((.) . (.)) (*!) (+!) :: Int -> Int -> Int -> Int
有些库以
(.:)
(like)的名称提供此功能。有时人们喜欢写它
fmap。fmap
(但这不仅仅是普通函数的组合)


但这有点神秘,因此通常避免使用。明确地写出函数几乎总是更清楚的。

这是一个有趣的问题

首先,我将解释为什么你会得到你所做的类型

(+)和(*)都具有类型

Num a=>a->a->a
这基本上意味着它们有两个数字作为输入,输出一个数字(正如加法和乘法所期望的那样)

函数组合将(a->b)类型的两个函数链接在一起(当然,第一个函数的输出需要与下一个函数的输入类型相同)

因此,乍一看,(+)或(*)似乎都不是那种类型。。。。除了在哈斯凯尔的世界里,你可以把他们看作是一种类型

(+)::Num a=>a->(a->a)
这是有道理的。。。。例如,如果您填入一个(+)值,您将得到一个函数,该函数将一个数字的值增加该值

(+) 1 --evaluates to incrementByOne
where incrementByOne x = 1+x
因此,您可以将这两个链接在一起,但是

记住(*)的输入必须是数字!(因为
numa=>

将(.)应用于(+)和(*)将生成您的类型

(Num (a -> a), Num a) => a -> (a -> a) -> a -> a
但是,它有一个奇怪的约束
Num(a->a)
,它规定一个函数必须是一个数字。这基本上是不应该做的,但是Haskell中没有禁止它的内容,因此编译器在这一点上没有抱怨。只有当您尝试使用该函数时,它才会执行检查

((+) . (*)) 1 (+ 1) 2

<interactive>:16:1:
    No instance for (Num (a0 -> a0)) arising from a use of ‘it’
    In a stmt of an interactive GHCi command: print it
(+).(*)1(+1)2
:16:1:
没有因使用“it”而产生的(Num(a0->a0))实例
在交互式GHCi命令的stmt中:打印它

三个输入具有正确的类型,但约束除外。。。。解释器在这里抱怨函数(+1)不是一个数字。

数字函数不是前奏曲中的
Num
,但是如果您自己或导入为
Num b=>a->b
编写一个
Num
实例,您可以满足这个要求。@genisage对不起,我不完全理解您的意思?我怎样才能满足这个要求?我主要是想了解这个类型意味着什么以及这个类型签名意味着什么,所以如果你能给出一个具体的例子,说明什么可以满足它(事实上,把它作为一个答案发布),这将帮助我加载;(+)=liftA2(+);(*)=liftA2(*);(-)=liftA2(-);否定=fmap否定;信号=fmap信号;abs=fmap absWow,这个数据合成链接非常棒,肯定澄清了很多。谢谢。@MikeH-R这将略过前面一点,但是关于透镜的讨论是沿着这种多元函数组合的思路进行的(以及关于组合
fmap
s的更一般的想法):太棒了,我一直在努力学习一些关于透镜的知识(上周写下了我的第一篇拙劣的半理解的实现)因此,非常感谢您的推荐。谢谢谢谢你,这就解释了我对它最初为什么要编译的误解。
(Num (a -> a), Num a) => a -> (a -> a) -> a -> a
((+) . (*)) 1 (+ 1) 2

<interactive>:16:1:
    No instance for (Num (a0 -> a0)) arising from a use of ‘it’
    In a stmt of an interactive GHCi command: print it