2013-04-04 39 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的內部和實驗兩一眼後,它似乎是它可以進行重構是一個小更廣義的覆蓋更多的功能。