7

只是一个快速的概念性问题,我目前正在尝试更好地学习和理解 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>
4

3 回答 3

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 代码对自己的内部结构知之甚少。

于 2013-04-05T00:01:00.267 回答
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 -> c它与a -> (b -> c)您可能编写的相同a -> dwhere 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

但是,当不知道函数的参数是否具有可类型类时,此方法不起作用,但是 while map (+1)will workmap将不起作用。

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

<interactive>:233:1:
...

在浏览了Data.Data一个或两个实验的内部之后,似乎可以将其重构为更通用一点,涵盖更多功能。

于 2013-04-06T01:32:25.423 回答
3

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

默认情况下,函数不是类型类的成员,所以我们不能打印它们。

我们可以使它成为类型类的成员

instance Show (a -> b) where
   show f = "Unicorns!!"

但是在这里我们意识到为什么默认情况下它没有实现。没有简单、明显的函数表示,haskell 不想猜测,因此没有实例。

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

此外,它是一个重要的编译器更改,Haskell 已编译,这意味着类似f = g

f =             g 

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

如果你真的想让它打印独角兽!!不过,请随意。

于 2013-04-04T23:59:49.107 回答