Mik*_*H-R 9 haskell composition
我的问题很简单,因为任何人开始使用haskell我一直在考虑类型,功能组成以及如何应用它们.我开始考虑((+) . (*))可能的结果.
现在很明显,这个问题的解决方案是开放ghci并找出答案.所以我这样做并检查了类型:
?> :t ((*) . (+))
((*) . (+)) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
Run Code Online (Sandbox Code Playgroud)
这种类型可能吗?我很难理解它可能是什么或它意味着什么?
再次为这个简单化的问题道歉,我试图加入到函数中的一切都失败了.我只是试图通过二元函数来开发函数组合的直觉.
不幸的是,GHC没有给出一个非常好的信息.这几乎肯定不是你想要的.Num (a -> a)默认情况下没有实例,并且实现一个实例,虽然它可能对某些事情有用,但可能导致非常不直观的运行时错误.即使在这种情况下,这个功能也不太可能有用.
让我们看看类型是否受限制(*)并(+)简化情况并避免类型类增加的复杂性:
(*!) :: Int -> Int -> Int
(*!) = (*)
(+!) :: Int -> Int -> Int
(+!) = (+)
Run Code Online (Sandbox Code Playgroud)
现在,当我们尝试
?> :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: (*!) . (+!)
Run Code Online (Sandbox Code Playgroud)
这表明我们没有应用(+!)足够的参数来将结果应用于(*!).如果我们扩展函数组合,我们会看到这一点,这可能会更清楚为什么它没有意义:
(*!) . (+!) == \x -> (*!) ((+!) x) -- definition of (.)
== \x y -> (*!) ((+!) x) y -- eta-expansion
== \x y -> ((+!) x) *! y -- changed (*.) from prefix to infix
Run Code Online (Sandbox Code Playgroud)
左边的参数(*!)是一个函数,它与预期的类型不匹配Int.
为了做到这一点,我们需要一个功能(b -> c) -> (a1 -> a2 -> b) -> a1 -> a2 -> c.幸运的是,这正是如此((.) . (.)).
?> :t ((.) . (.)) (*!) (+!)
((.) . (.)) (*!) (+!) :: Int -> Int -> Int -> Int
Run Code Online (Sandbox Code Playgroud)
有些库在名称下提供此功能(.:)(如此).有时人们喜欢写它fmap . fmap(虽然这不仅仅是普通的功能组合).
虽然它有点神秘,但通常会因此而避免.只是明确地写出函数几乎总是更清楚.
这是一个有趣的问题....
首先,我将解释为什么你得到你所做的类型.
(+)和(*)都有类型
Num a=>a->a->a
Run Code Online (Sandbox Code Playgroud)
这基本上意味着他们有两个数字作为输入,并输出一个数字(应该从添加和乘法预期)
函数组合将类型(a-> b)的两个函数链接在一起(当然,第一个的输出需要与下一个的输入相同).
(.)::(b->c)->(a->b)->a->c
Run Code Online (Sandbox Code Playgroud)
所以,乍一看,(+)或(*)似乎都不属于那种类型......除了在Haskell的世界中,你可以将它们视为类型
(+)::Num a=>a->(a->a)
Run Code Online (Sandbox Code Playgroud)
这是有意义的....如果你填入一个(+)的值,你得到一个函数,增加一个数字的值,例如
(+) 1 --evaluates to incrementByOne
where incrementByOne x = 1+x
Run Code Online (Sandbox Code Playgroud)
所以,你可以把两者连在一起,但.....
请记住,(*)的输入必须是数字!(因为Num a=>)
将(.)应用于(+)和(*)会产生您的类型
(Num (a -> a), Num a) => a -> (a -> a) -> a -> a
Run Code Online (Sandbox Code Playgroud)
但是,它有一个奇怪的约束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
Run Code Online (Sandbox Code Playgroud)
三个输入具有正确的类型,除了约束....解释器在这里抱怨函数(+ 1)不是数字.
| 归档时间: |
|
| 查看次数: |
154 次 |
| 最近记录: |