我写了一个更高阶的Haskell函数,如下所示,
higherOrderFun f p xs = (map f) (filter p xs)
适用于以下
higherOrderFun (\x -> 2 * x) odd [1..4]
but throws an error for
higherOrderFun sin odd [1..4]
这是堆栈跟踪:
No instance for (Show b0) arising from a use of ‘print’
The type variable ‘b0’ is ambiguous
Note: there are several potential instances:
instance Show Double -- Defined in ‘GHC.Float’
instance Show Float -- Defined in ‘GHC.Float’
instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
-- Defined in ‘GHC.Real’
...plus 23 others
In a stmt of an interactive GHCi command: print it
任何调试指针?
答案 0 :(得分:7)
这里的问题是odd
和sin
的概念互动。您不能使用非浮点sin
,浮点数不能为odd
(或even
。为了探索的目的,GHCI试图给你带来怀疑的好处,因此它没有为higherOrderFun sin odd [1..4]
的输出分配具体类型,而是倾向于推断出在概念上不存在的类型(即{ {1}})。当您尝试打印值时,这会回过头来咬你,因为不存在的推断类型当然可以没有(Integral b, Floating b) => [b]
的实例。这不仅限于Show
:任何尝试分配具体类型(调用show
,手动分配例如odd
等)都会失败。
GHC更挑剔。如果您将其粘贴在:: Double
文件中并尝试编译它,GHC会抱怨,因为它无法推断出.hs
的连贯类型
higherOrderFun
关于module Main where
higherOrderFun f p xs = (map f) (filter p xs)
main :: IO ()
main = do
let x = higherOrderFun (\x -> 2 * x) odd [1..4]
y = higherOrderFun (sin) odd [1..4]
print (x, y)
{-
[1 of 1] Compiling Main ( /tmp/test.hs, /tmp/test.o )
/tmp/test.hs:8:29:
No instance for (Floating b0) arising from a use of ‘sin’
The type variable ‘b0’ is ambiguous
Relevant bindings include y :: [b0] (bound at /tmp/test.hs:8:9)
Note: there are several potential instances:
instance Floating Double -- Defined in ‘GHC.Float’
instance Floating Float -- Defined in ‘GHC.Float’
In the first argument of ‘higherOrderFun’, namely ‘(sin)’
In the expression: higherOrderFun (sin) odd [1 .. 4]
In an equation for ‘y’: y = higherOrderFun (sin) odd [1 .. 4]
/tmp/test.hs:8:34:
No instance for (Integral b0) arising from a use of ‘odd’
The type variable ‘b0’ is ambiguous
Relevant bindings include y :: [b0] (bound at /tmp/test.hs:8:9)
Note: there are several potential instances:
instance Integral Int -- Defined in ‘GHC.Real’
instance Integral Integer -- Defined in ‘GHC.Real’
instance Integral GHC.Types.Word -- Defined in ‘GHC.Real’
In the second argument of ‘higherOrderFun’, namely ‘odd’
In the expression: higherOrderFun (sin) odd [1 .. 4]
In an equation for ‘y’: y = higherOrderFun (sin) odd [1 .. 4]
/tmp/test.hs:8:38:
No instance for (Enum b0)
arising from the arithmetic sequence ‘1 .. 4’
The type variable ‘b0’ is ambiguous
Relevant bindings include y :: [b0] (bound at /tmp/test.hs:8:9)
Note: there are several potential instances:
instance Enum Double -- Defined in ‘GHC.Float’
instance Enum Float -- Defined in ‘GHC.Float’
instance Integral a => Enum (GHC.Real.Ratio a)
-- Defined in ‘GHC.Real’
...plus 7 others
In the third argument of ‘higherOrderFun’, namely ‘[1 .. 4]’
In the expression: higherOrderFun (sin) odd [1 .. 4]
In an equation for ‘y’: y = higherOrderFun (sin) odd [1 .. 4]
/tmp/test.hs:8:39:
No instance for (Num b0) arising from the literal ‘1’
The type variable ‘b0’ is ambiguous
Relevant bindings include y :: [b0] (bound at /tmp/test.hs:8:9)
Note: there are several potential instances:
instance Num Double -- Defined in ‘GHC.Float’
instance Num Float -- Defined in ‘GHC.Float’
instance Integral a => Num (GHC.Real.Ratio a)
-- Defined in ‘GHC.Real’
...plus three others
In the expression: 1
In the third argument of ‘higherOrderFun’, namely ‘[1 .. 4]’
In the expression: higherOrderFun (sin) odd [1 .. 4]
/tmp/test.hs:9:5:
No instance for (Show b0) arising from a use of ‘print’
The type variable ‘b0’ is ambiguous
Relevant bindings include y :: [b0] (bound at /tmp/test.hs:8:9)
Note: there are several potential instances:
instance Show Double -- Defined in ‘GHC.Float’
instance Show Float -- Defined in ‘GHC.Float’
instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
-- Defined in ‘GHC.Real’
...plus 24 others
In a stmt of a 'do' block: print (x, y)
In the expression:
do { let x = higherOrderFun (\ x -> ...) odd ...
y = higherOrderFun (sin) odd ...;
print (x, y) }
In an equation for ‘main’:
main
= do { let x = ...
....;
print (x, y) }
-}
"工作":当map sin [1..4]
打印某些内容时,它map sin [1..4]
没有相同的限制。 GHCI将简单推断odd
是[1..4]
的列表并采取相应行动。
调试此问题的最佳方式(我发现)是使用GHCI中的Double
和:t
命令。 GHCI会议的一个例子:
:i
马上,这种类型看起来很可疑。应该没有Prelude PrettyGHCI> let higherOrderFun f p xs = (map f) (filter p xs)
Prelude PrettyGHCI> :t higherOrderFun sin odd [1..4]
higherOrderFun sin odd [1..4] :: (Integral b, Floating b) => [b]
和Integral
的类型。我们可以使用Floating
:
:i
我稍微清理了输出,所以在这里显而易见的是,Prelude PrettyGHCI> :i Floating
instance Floating Float
instance Floating Double
Prelude PrettyGHCI> :i Integral
instance Integral Integer
instance Integral Int
和Floating
中的类型没有重叠。
此时,您基本上有两个选择
放弃不是一个有效的选择,所以我们说服这些类型玩得很好:
Integral
这给了我们一个很好的,有效的多态类型。 Prelude PrettyGHCI> :t higherOrderFun (sin . fromIntegral) odd [1..4]
higherOrderFun (sin . fromIntegral) odd [1..4] :: Floating b => [b]
(Floating
和Float
)的两种类型居民都有Double
个实例,因此您的工作已完成。
请注意,我们之所以这样做是因为所有Show
类型都必须为Floating
。 Fractional
提供了一个函数Fractional
。 fromRational :: Rational -> a
类型必须为Integral
,Real
提供函数Real
。 toRational :: a -> Rational
只是定义为fromIntegral :: (Num b, Integral a) => a -> b
。
答案 1 :(得分:3)
如果您看一下,sin
的类型为sin :: Floating a => a -> a
,但您的列表的类型为(filter odd [1..4]) :: Integral a => [a]
。因此,您遇到了失败。
但是,
higherOrderFun (sin . fromIntegral) odd [1..4]
返回
[0.8414709848078965,0.1411200080598672]
干杯,祝你好运。
答案 2 :(得分:2)
odd
仅适用于Integral
值(instance
类型类型Integral
类型的值)。 sin
仅适用于Floating
个。 higherOrderFun sin odd [1..4]
的类型是
>:t higherOrderFun sin odd [1..4]
higherOrderFun sin odd [1..4] :: (Integral b, Floating b) => [b]
要使用此功能,您需要一个同时具有Integral
和Floating
的类型,并且基本库中不存在任何类型(也不应该存在)。您可以使用Num
Floating
类型的值设置任何Integral
类型的值,从而设置任何fromIntegral :: (Integral a, Num b) => a -> b
类型的值
>:t higherOrderFun (sin . fromIntegral) odd [1..4]
higherOrderFun (sin . fromIntegral) odd [1..4] :: Floating b => [b]
这只需要Floating
个实例来获得结果。 ghci将使用Double
对此进行评估,Floating
是需要Prelude> higherOrderFun (sin . fromIntegral) odd [1..4]
[0.8414709848078965,0.1411200080598672]
实例的未知类型的默认值。
{{1}}