2013-04-04 50 views
6

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

您希望为该功能生成什么'String'? Jynx! – 2013-04-06 15:43:04

回答

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对其内部的代码知之甚少。

+2

实际上内置了一个'Show'实例。这是一些常见问题 - [这里](http://stackoverflow.com/questions/15015698/derive-eq-and-show-for-type-alias-in-例如,haskell/15015731#15015731)和[here](http://stackoverflow.com/questions/10551210/instance-show-for-function-function/10551513#10551513)。 – 2013-04-05 03:22:02

3

show是在属于Show类型类的成员函数中定义的函数(如果你不知道一个类型类是什么,它有点像一个面向对象的接口)。

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

我们可以把它的类型类与

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

成员,但在这里,我们意识到它为什么不会默认执行。没有简单的,明显的函数表示,而且haskell不想猜测,因此没有实例。

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

进一步这是一个平凡的编译器的变化,Haskell的编译,这意味着像f = g

f =    g 

东西之间的差异完全失去它。但是你一定会在你的函数表示中想要这个。正因为如此,你必须在整个程序中绕过这个字符串。这绝对不是你想要的二进制文件。

如果你真的想要它打印独角兽!尽管如此,感觉自由。

+0

!我认为值得注意的是为什么编译器需要(大)更改:编译Haskell去掉代码的许多细节。 – amindfv 2013-04-05 00:04:53

+0

公平地说,用ghc,中间语言保留了大量的信息,然而实际的函数文本,比如空白,在解析后消失并且永远消失。 Ps“独角兽!!”比“功能”更具信息性。 :P – jozefg 2013-04-05 00:06:46

+4

也可以使用一个参数,在语义上,'\ x - > 3 * x'和'\ x - > x * 3'是相同的函数(至少在'Int'上),所以您要么任意选择一个字符串来表示它们,或者在'IO'单元中进行区分。 – hammar 2013-04-05 00:16:04

7

对于使用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 

该解决方案适用于多种功能arities因为a -> b -> c相同a -> (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的内部和实验两一眼后,它似乎是它可以进行重构是一个小更广义的覆盖更多的功能。