2013-04-04 9 views
6

簡単な概念的な質問ですが、私は現在、ハスケルをよりよく理解し、理解しようとしています。関数のShowインスタンスがないのはなぜですか?

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

その関数で生成される文字列は、どのようなものでしょうか? –

答えて

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'インスタンスが組み込まれています。これはFAQの何かです - [here](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/10551513#10551513)などがあります。 –

3

showShow型クラス(あなたは型クラスが何であるかわからない場合、それはちょっとOOPインターフェイスのようなものだ)のメンバーである関数に定義されている機能です。

デフォルトでは、関数はtypeclassのメンバーではないため、それらは印刷できません。

は、我々はそれ

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

と型クラスのメンバーで作ることができますが、ここで我々はそれがデフォルトで実装されていない理由を実現しています。関数の単純明示的表現はなく、haskellは推測したくないので、インスタンスはありません。

唯一の "許容される"インスタンスは、実際に関数を出力するものですが、実際の言語の変更が必要です。つまり、コンパイラにハードワイヤード接続されている場合があります。それは役に立つかもしれない。

は、さらに多くのことが自明でないコンパイラの変更だ、Haskellは完全にそれに失われf = g

f =    g 

のようなものとの違いを意味してコンパイルされています。しかし、間違いなくあなたの関数表現でそれを望むでしょう。このため、プログラムを通してこの文字列の周りを抱かせる必要があります。これは間違いなくあなたがバイナリで望むものではありません。

本当にユニコーンを印刷したい場合は!!でも、気軽に。

+0

Jynx!私はそれがなぜコンパイラの変更が必要になるのか注目する価値があると考えています。Haskellをコンパイルすることでコードの詳細が取り除かれます。 – amindfv

+0

ghcでは公平で、中間言語は相当量の情報を保持しますが、実際の関数テキスト(空白のようなもの)は解析後に消滅し、永遠に失われます。 Ps "ユニコーン!!" 「A関数」よりもはるかに有益です。 :P – jozefg

+4

意味的に、 '\ x - > 3 * x'と' \ x - > x * 3'は同じ関数です(少なくとも 'Int'では)。それらを区別するために 'IO'モナドで動作するかのどちらかを指定するために、任意に1つの文字列を選択します。 – hammar

7

Data.Typeableを使用するすべての関数の固定ストリングを超える部分的な解決策があります。 GHCiの

残念ながら
> let test :: Int->Int; test x = x + x 
> test 
Int -> Int 

{-# LANGUAGE ScopedTypeVariables #-} 

import Data.Typeable 

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

型シグネチャなしのタイプがデフォルトとそれに行きます。 a -> b -> cはあなたにもa -> dd = b -> cとして書くかもしれないa -> (b -> c)と同じであるため、

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

このソリューションは、複数の関数アリティに取り組んでいます。

> 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はしません動作しますが、関数のパラメータはのでしかしtypeableクラスを持っている場合、それが不明な場合、この方法は、しかし、動作しません。

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

<interactive>:233:1: 
... 

より多くの機能をもう少し一般的なカバーであることをリファクタリングすることができようにData.Dataと実験や2の内部をちらっと見た後に思えます。

関連する問題