2013-04-04 25 views
6

Solo una rapida domanda concettuale, attualmente sto cercando di imparare e capire meglio Haskell.Perché non c'è nessuna istanza per le funzioni?

So che la funzione Show viene utilizzata per convertire i valori in stringhe, ma perché non è possibile utilizzare i tipi di funzione con 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

Quale 'stringa 'ti aspetteresti di produrre per quella funzione? –

risposta

10

Non è che non possono, ma che di solito non c'è una buona ragione per farlo.

Ma se vuoi, è sicuramente possibile:

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. 

Se desideri show la rappresentazione testuale della funzione, così - non si può fare. A differenza dei linguaggi di metaprogrammazione come Ruby, JS, ecc., Haskell codifica pochissima conoscenza dei propri interni.

+2

In realtà c'è un'istanza 'Show' integrata. Questa è una specie di FAQ - [qui] (http://stackoverflow.com/questions/15015698/derive-eq-and-show-for-type-alias-in- haskell/15015731 # 15015731) e [qui] (http://stackoverflow.com/questions/10551210/instance-show-for-function/10551513#10551513) ad esempio. –

3

show è la funzione che è definita sulle funzioni che sono membri delle Show typeclass (se non si sa che cosa un typeclass è, è un po 'come un'interfaccia OOP).

Per impostazione predefinita, le funzioni non sono membri della classe di tipi, quindi non possiamo stamparle.

Potremmo fare un membro del typeclass con

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

ma qui ci rendiamo conto perché non è implementata per impostazione predefinita. Non c'è una rappresentazione semplice e ovvia delle funzioni e haskell non vuole indovinare, e quindi nessuna istanza.

L'unica istanza "consentita" sarebbe quella che stampa effettivamente la funzione, ma ciò richiederebbe un cambio di lingua effettivo, cioè sarebbe cablato nel compilatore, il che non vale la pena per i pochi casi in cui potrebbe essere utile

ulteriormente più è un cambiamento compilatore non banale, Haskell è stato compilato il che significa che le differenze tra qualcosa come f = g e

f =    g 

sono interamente perdute su di esso. Ma lo vorresti sicuramente nella rappresentazione della tua funzione. Per questo motivo, dovresti trascinare questa stringa attraverso il programma. Questo non è sicuramente quello che vuoi in un binario.

Se davvero vuoi stampare unicorni !! comunque, sentiti libero.

+0

Jynx! Penso che valga la pena notare perché sarebbero necessarie (grandi) modifiche al compilatore: la compilazione di Haskell elimina molti dettagli del codice. – amindfv

+0

Beh, in tutta onestà, con ghc, i linguaggi intermedi mantengono una discreta quantità di informazioni, tuttavia il testo della funzione effettiva, cioè gli spazi come gli spazi, svanisce dopo l'analisi e scompare per sempre. Ps "Unicorno !!" è molto più informativo di "Una funzione". : P – jozefg

+4

Un argomento potrebbe anche essere fatto che semanticamente, '\ x -> 3 * x' e' \ x -> x * 3' sono la stessa funzione (almeno su 'Int'), quindi avresti o scegliere arbitrariamente una stringa per rappresentarle entrambe o lavorare nella monade 'IO' per distinguerle. – hammar

7

Esiste una soluzione parziale che va oltre la semplice stringa fissa per tutte le funzioni utilizzando Data.Typeable.

{-# LANGUAGE ScopedTypeVariables #-} 

import Data.Typeable 

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

in ghci

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

Purtroppo senza una firma tipo il tipo andrà a IT predefinito.

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

questa soluzione funziona su più arietà funzione perché a -> b -> c è lo stesso di a -> (b -> c) che si potrebbe anche scrivere come a -> d dove 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 

Questo metodo non funziona tuttavia quando non si sa se i parametri della funzione hanno la classe tipizzabile però così mentre map (+1) funzionerà map no.

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

<interactive>:233:1: 
... 

Dopo guardando la struttura interna di Data.Data e un esperimento o due sembra che potrebbe essere riscritta per essere le funzioni di copertura più un po 'più generalizzata.

Problemi correlati