Haskell:使用两个浮动参数组合函数失败
我试图将Haskell:使用两个浮动参数组合函数失败,haskell,function-composition,Haskell,Function Composition,我试图将(浮动a)=>a->a->a类型的函数与(浮动a)=>a->a类型的函数组合,以获得(浮动a)=>a->a类型的函数。我有以下代码: test1 :: (Floating a) => a -> a -> a test1 x y = x test2 :: (Floating a) => a -> a test2 x = x testBoth :: (Floating a) => a -> a -> a testBoth = test2 .
(浮动a)=>a->a->a
类型的函数与(浮动a)=>a->a
类型的函数组合,以获得(浮动a)=>a->a
类型的函数。我有以下代码:
test1 :: (Floating a) => a -> a -> a
test1 x y = x
test2 :: (Floating a) => a -> a
test2 x = x
testBoth :: (Floating a) => a -> a -> a
testBoth = test2 . test1
--testBoth x y = test2 (test1 x y)
但是,当我在GHCI中编译它时,我得到以下错误:
/path/test.hs:8:11:
Could not deduce (Floating (a -> a)) from the context (Floating a)
arising from a use of `test2'
at /path/test.hs:8:11-15
Possible fix:
add (Floating (a -> a)) to the context of
the type signature for `testBoth'
or add an instance declaration for (Floating (a -> a))
In the first argument of `(.)', namely `test2'
In the expression: test2 . test1
In the definition of `testBoth': testBoth = test2 . test1
Failed, modules loaded: none.
请注意,注释掉的testBoth
版本可以编译。奇怪的是,如果我从所有类型签名中删除(浮动a)
约束,或者如果我将test1
更改为只取x
,而不是x
和y
,testBoth
编译
我搜索了StackOverflow、Haskell wikis、Google等,没有发现任何与此特定情况相关的函数组合限制。有人知道为什么会这样吗
\x y -> test2 (test1 x y)
== \x y -> test2 ((test1 x) y)
== \x y -> (test2 . (test1 x)) y
== \x -> test2 . (test1 x)
== \x -> (test2 .) (test1 x)
== \x -> ((test2 .) . test1) x
== (test2 .) . test1
这两样东西不一样
test2 . test1
== \x -> (test2 . test1) x
== \x -> test2 (test1 x)
== \x y -> (test2 (test1 x)) y
== \x y -> test2 (test1 x) y
您的问题与浮动无关,尽管typeclass确实使您的错误更难理解。以下面的代码为例:
test1 :: Int -> Char -> Int
test1 = undefined
test2 :: Int -> Int
test2 x = undefined
testBoth = test2 . test1
这两种测试的类型是什么?好的,我们采用(::(b->c)->(a->b)->a->c的类型,转动曲柄得到:
b~Int
(test2的参数与()
的第一个参数统一)
c~Int
(test2
的结果与(.
)的第一个参数的结果统一)
a~Int
(test1
参数1与(.)的参数2统一)
b~Char->Int
(测试1的结果与()
的参数2统一)Char->Int
)必须与test2
(#1,Int
)的参数类型统一。哦,不
你应该怎么做?正确的解决方案是:
testBoth x = test2 . test1 x
有其他的方法,但我认为这是最可读的。< /P>
编辑:那么,试图告诉你的错误是什么?有人说,将
浮动a=>a->a
与浮动b=>b
统一需要实例浮动(a->a)
。。。虽然这是真的,但您确实不希望GHC尝试将函数视为浮点数。您的问题与浮点数无关,而是您希望以不进行类型检查的方式组合一个具有两个参数的函数和一个具有一个参数的函数。我将给出一个组合函数<代码>反转的例子。foldr(:)[]
相反。foldr(:)[]
的类型为[a]->[a]
并按预期工作:它返回一个反向列表(foldr(:)[]
基本上用于列表)
然而,相反。foldr(:)
不进行类型检查。为什么?
当类型与函数组合匹配时
让我们回顾一些类型:
reverse :: [a] -> [a]
foldr (:) :: [a] -> [a] -> [a]
foldr (:) [] :: [a] -> [a]
(.) :: (b -> c) -> (a -> b) -> a -> c
相反。foldr(:)[]
类型检查,因为()
实例化为:
(.) :: ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
换句话说,在()
的类型注释中:
变成a
[a]
变成b
[a]
变成c
[a]
[a]->[a]
当类型与函数组合不匹配时
相反。foldr(:)
不进行类型检查,因为:
foldr (:) :: [a] -> [a] -> [a]
作为()
的正确操作符,它将把它的类型从a->b
实例化为[a]->([a]->[a])
。即:
(b -> c) -> (a -> b) -> a -> c
- 类型变量
将替换为a
[a]
- 类型变量
将替换为b
[a]->[a]
foldr(:)
的类型为a->b
,则(.foldr(:)
的类型为:
(b -> c) -> a -> c`
(foldr(:)
作为右操作符应用于()
)
但是因为foldr(:)
的类型是[a]->([a]->[a])
,所以(.foldr(:)
的类型是:
(([a] -> [a]) -> c) -> [a] -> c
相反。foldr(:)
不进行类型检查,因为reverse
的类型是[a]->[a]
,而不是([a]->[a])->c
猫头鹰操作员
当人们第一次在Haskell中学习函数组合时,他们了解到当函数的最后一个参数位于函数体的最右边时,可以从参数和函数体中删除它,用点替换括号(或美元符号)。换句话说,以下4个函数定义是等效的:
f a x xs = g . h a . i x $ xs
f a x xs = g . h a . i $ x xs
所以人们有一种直觉说“我只是从主体和参数中移除最右边的局部变量”,但这种直觉是错误的,因为一旦你移除了xs
f a x = g . h a . i x
f a = g . h a . i
他们不是对等的!您应该了解函数组合类型何时检查,何时不检查。如果上述2项是等效的,则意味着以下2项也是等效的:
f a x xs = g . h a . i x $ xs
f a x xs = g . h a . i $ x xs
这毫无意义,因为x
不是一个以xs
作为参数的函数x
是函数i
的参数,xs
是函数(ix)
的参数
有一个技巧可以使一个具有两个参数的函数无点。也就是说,使用“owl”操作符:
f a x xs = g . h a . i x xs
f a = g . h a .: i
where (.:) = (.).(.)
上述两个函数定义是等效的。阅读
工具书类
一旦您了解了函数、类型、部分应用程序和货币化、函数组合和美元运算符,Haskell编程就变得简单明了了。要明确这些概念,请阅读以下答案:
- 在
- 在
- 在
- 在
- 在
- 在
- 在