我在此代码中列出的类型有点麻烦:
distance :: (Floating a) => (a, a) -> (a, a) -> a
distance (x1, y1) (x2, y2) = sqrt $ (x2 - x1)**2 + (y2 - y1)**2
gravitation :: (Num a, Floating a) => (a,a) -> (a,a) -> a
gravitation = ((**) (-1.0)) . ((**) 2.0) . distance
我的印象是,由于distance
会返回Floating
个变量,我可以将其输入((**) 2.0)
。有没有解决这个问题,同时保持代码相对优雅?
我得到的错误是:
Main.hs:13:16:
Could not deduce (Floating ((a, a) -> a))
arising from a use of `**'
from the context (Num a, Floating a)
bound by the type signature for
gravitation :: (Num a, Floating a) => (a, a) -> (a, a) -> a
at Main.hs:12:16-57
Possible fix:
add an instance declaration for (Floating ((a, a) -> a))
In the first argument of `(.)', namely `((**) (- 1.0))'
In the expression: ((**) (- 1.0)) . ((**) 2.0) . distance
In an equation for `gravitation':
答案 0 :(得分:2)
问题是distance
有两个参数,你需要一个与两个一起使用的合成运算符。 There's a package那里定义了方便的,但它很容易记住:
infixr 9 .:
(.:) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.).(.)
现在你应该能够做到
gravitation = (negate 1 **) . (2 **) .: distance
infixr 9
很重要,它将.:
运算符的固定性设置为与.
运算符相同。我总是很快用:i (.)
在GHCi中检查这个,因为谁有时间记住这些东西?每当我看到这个问题时,我总是想指出这个运算符使用fmap
有一个更通用的形式:
(.:) :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
(.:) = fmap fmap fmap
从技术上讲,这些fmap
中的第一个用于函数仿函数,因此它也与fmap . fmap
相同。这个更通用的形式简单地fmap
是一个2层深的函数,并且在函数是你的函子的情况下,它结果是这个方便的组合运算符。但它有其他用途:
(+1) .: [Just 1, Nothing, Just 3]
[Just 2, Nothing, Just 4]
同样,它只是将(+1)
两个仿函数层应用于深层,这就是它。