为什么函数没有Show实例?

时间:2013-04-04 23:55:16

标签: haskell

只是一个简单的概念性问题,我目前正在努力学习和更好地理解Haskell。

我知道Show函数用于将值转换为字符串,但为什么函数类型不能与show一起使用?

Prelude> (\x -> x*3)

<interactive>:7:1:
    No instance for (Show (a0 -> a0))
      arising from a use of `print'
    Possible fix: add an instance declaration for (Show (a0 -> a0))
    In a stmt of an interactive GHCi command: print it
Prelude>

3 个答案:

答案 0 :(得分:10)

并非他们不能,但通常没有充分的理由。

但如果你愿意,你绝对可以:

Prelude> :{
Prelude| instance Show (a -> b) where
Prelude|    show _ = "A function."
Prelude| :}
Prelude> print (\x -> x + 7)
A function.
Prelude> print (\a b c -> a + b + c)
A function.

如果你想show函数的文本表示,那么你就不能这样做。与Ruby,JS等元编程语言不同,Haskell对其内部的代码知之甚少。

答案 1 :(得分:8)

有一个部分解决方案超出了使用Data.Typeable的所有函数的固定字符串。

{-# LANGUAGE ScopedTypeVariables #-}

import Data.Typeable

instance (Typeable a, Typeable b) => Show (a->b) where
  show _ = show $ typeOf (undefined :: a -> b)

在ghci

> let test :: Int->Int; test x = x + x
> test
Int -> Int

不幸的是,没有类型签名,类型将默认为。

> let test x = x + x
> test
Integer -> Integer

此解决方案适用于多个功能元素,因为a -> b -> ca -> (b -> c)相同,您可以将a -> d写为d = b -> c

> let m10 a b c d e f g h i j = a * b * c * d * e * f * g * h* i * j
> m10
Integer -> Integer -> Integer -> Integer -> Integer -> Integer -> Integer
        -> Integer -> Integer -> Integer -> Integer

但是,当不知道函数的参数是否具有可键入的类时,此方法不起作用,但map (+1)将起作用map则不会。

> map (+1)
[Integer] -> [Integer]
> map

<interactive>:233:1:
...

在看了Data.Data的内部和一两个实验后,似乎可以重构为更广泛的覆盖更多功能。

答案 2 :(得分:3)

show是在作为Show类型类成员的函数上定义的函数(如果您不知道类型类是什么,它有点像OOP接口)。

默认情况下,函数不是类型类的成员,因此我们无法打印它们。

我们可以使用

使其成为类型类的成员
instance Show (a -> b) where
   show f = "Unicorns!!"

但是我们在这里意识到为什么它没有默认实现。没有一个简单明了的函数表示,而且haskell不想猜测,因此没有实例。

唯一的“允许”实例将是实际打印出函数的实例,但这需要实际的语言更改,即它将被硬连线到编译器中,这对于它的少数情况来说是不值得的。可能有用。

此外,它是一个非常重要的编译器更改,编译Haskell意味着f = g

之间的差异
f =             g 

完全迷失了。但你肯定希望在你的函数表示中。因此,你必须在整个程序中使用此字符串。这绝对不是你想要的二进制文件。

如果你真的想要它打印独角兽!!但是,请随意。