2013-04-04 17 views
6

Po prostu szybkie pytanie koncepcyjne, obecnie staram się lepiej poznać i zrozumieć Haskell.Dlaczego nie ma wystąpienia wystąpienia dla funkcji?

Wiem, że funkcja Show służy do konwertowania wartości na ciągi, ale dlaczego nie można używać typów funkcji w programie?

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

Jakiego "łańcucha" można się spodziewać do wykonania tej funkcji? –

Odpowiedz

10

To nie tak, że nie mogą, ale zwykle nie ma dobrego powodu.

Ale jeśli chcesz, na pewno można:

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. 

Jeśli chcesz show reprezentację tekstową funkcją, dobrze - nie można tego zrobić. W przeciwieństwie do języków programowania metaprogramowego, takich jak Ruby, JS, itp., Haskell koduje bardzo mało wiedzy o swoich wewnętrznych cechach.

+2

W rzeczywistości jest wbudowana instancja 'Show'. Jest to coś z FAQ - [tutaj] (http://stackoverflow.com/questions/15015698/derive-eq-and-show-for-type-alias-in- haskell/15015731 # 15015731) i [tutaj] (http://stackoverflow.com/questions/10551210/instance-show-for-function/10551513 #10551513) na przykład. –

3

show jest funkcja, która jest określona na funkcjach, które są członkami Show typeclass (jeśli nie wiesz co to typeclass jest to trochę jak interfejs OOP).

Domyślnie funkcje nie są członkami typografii, więc nie możemy ich wydrukować.

mogliśmy uczynić go członkiem typeclass z

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

ale tutaj możemy zrozumieć, dlaczego nie jest realizowany domyślnie. Nie ma prostej, oczywistej reprezentacji funkcji, a haskell nie chce zgadywać, a zatem nie ma instancji.

Jedyną "dopuszczalną" instancją byłaby taka, która faktycznie wypisuje funkcję, ale wymagałoby to rzeczywistej zmiany języka, tj. Byłaby podłączona do kompilatora, co po prostu nie jest tego warte w nielicznych przypadkach, w których może być przydatne.

Co więcej jest to nietrywialne zmiana kompilator, Haskell jest kompilowany, co oznacza różnicę między coś takiego f = g i

f =    g 

są całkowicie stracił na niego. Ale na pewno chcesz tego w swojej reprezentacji funkcji. Z tego powodu będziesz musiał przeciągnąć ten ciąg przez cały program. To zdecydowanie nie jest to, czego chcesz w systemie binarnym.

Jeśli naprawdę chcesz wydrukować jednorożce !! choć czuję się swobodnie.

+0

Jynx! Myślę, że warto zauważyć, dlaczego (duże) zmiany w kompilatorze byłyby wymagane: kompilowanie Haskella usuwa wiele szczegółów kodu. – amindfv

+0

Dobrze w uczciwości, z ghc, języki pośrednie zachowują sporo informacji, jednak rzeczywisty tekst funkcyjny, tj. Rzeczy takie jak białe spacje, znikają po analizie i znikną na zawsze. Ps "Jednorożec !!" jest o wiele bardziej pouczający niż "funkcja". : P – jozefg

+4

Można również argumentować, że semantycznie, '\ x -> 3 * x' i' \ x -> x * 3' są tą samą funkcją (przynajmniej w 'Int'), więc albo arbitralnie wybiera jeden ciąg znaków, aby reprezentować je lub pracować w monadzie "IO", aby je rozróżnić. – hammar

7

Istnieje częściowe rozwiązanie, które wykracza poza stały ciąg dla wszystkich funkcji korzystających z Data.Typeable.

{-# LANGUAGE ScopedTypeVariables #-} 

import Data.Typeable 

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

w ghci

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

Niestety bez podpisu typu typ pójdzie to domyślne.

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

To rozwiązanie działa na wielu arities funkcyjnych ponieważ a -> b -> c jest taka sama jak a -> (b -> c) które równie dobrze można napisać jak a -> d gdzie 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 

Metoda ta nie działa jednak, gdy nie wiadomo, czy parametry funkcji mają typeable klasę jednak tak podczas map (+1) zadziała map nie będzie.

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

<interactive>:233:1: 
... 

Po spoglądając na wewnętrznych części Data.Data i doświadczeniu lub dwóch wydaje się, że może to być refactored się nieco bardziej uogólnione obejmować więcej funkcji.

Powiązane problemy