调用高阶函数时出错

Sre*_*nat 1 haskell ghci

我写了一个更高阶的Haskell函数如下,

higherOrderFun f p xs = (map f) (filter p xs)
Run Code Online (Sandbox Code Playgroud)

它适用于以下情况

higherOrderFun (\x -> 2 * x) odd [1..4]

but throws an error for

higherOrderFun sin odd [1..4]
Run Code Online (Sandbox Code Playgroud)

这是堆栈跟踪:

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
Run Code Online (Sandbox Code Playgroud)

有没有调试指针?

Ell*_*son 7

这里的问题是概念的互动oddsin.你不能采用sin非浮点数,浮点数不能odd(或者even就此而言).为了探索的目的,GHCI试图给你怀疑的好处,所以它没有为输出分配一个具体的类型higherOrderFun sin odd [1..4],更喜欢推断一个概念上不存在的类型(即(Integral b, Floating b) => [b]).当您尝试打印值时,这会回来咬你,因为不存在的推断类型(当然)没有实例Show.这不限于show:任何分配具体类型(调用odd,手动分配例如:: Double等)的尝试都失败.

GHC更挑剔.如果你把它粘在一个.hs文件中并尝试编译它,GHC会抱怨,因为它不能推断出一个连贯的类型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) }
-}
Run Code Online (Sandbox Code Playgroud)

关于map sin [1..4]"工作":在map sin [1..4]打印某些东西时,它没有相同的限制odd.GHCI将简单推断[1..4]是一个Doubles 列表并相应地采取行动.

调试

调试的最好方法(我发现)是使用GHCI中的:t:i命令.GHCI会议的一个例子:

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]
Run Code Online (Sandbox Code Playgroud)

马上,这种类型看起来很可疑.应该没有两种类型的IntegralFloating.我们可以查看:i:

Prelude PrettyGHCI> :i Floating
instance Floating Float
instance Floating Double
Prelude PrettyGHCI> :i Integral
instance Integral Integer
instance Integral Int
Run Code Online (Sandbox Code Playgroud)

我清理输出位,所以它应该是显而易见这里有在居住类型没有重叠FloatingIntegral.

此时,您基本上有两种选择

  1. 放弃
  2. 说服这些类型玩得很好

放弃不是一个有效的选择,所以我们说服类型玩得很好:

Prelude PrettyGHCI> :t higherOrderFun (sin . fromIntegral) odd [1..4]
higherOrderFun (sin . fromIntegral) odd [1..4] :: Floating b => [b]
Run Code Online (Sandbox Code Playgroud)

这给了我们一个很好的,有效的多态类型.Floating(FloatDouble)两种类型的居民都有Show实例,因此你的工作已经完成.

请注意,我们可以这样做的原因是因为所有Floating类型都是必需的Fractional.Fractional提供一个功能fromRational :: Rational -> a.Integral类型是必需的Real,并Real提供一个功能toRational :: a -> Rational.fromIntegral :: (Num b, Integral a) => a -> b简单地定义为fromRational . toRational.