2015-03-22 8 views
20
Prelude> let myprint = putStrLn . show 
Prelude> :t myprint 
myprint ::() -> IO() 

OK, tutaj nic nadzwyczajnego. Tylko reguły domyślne typu GHCi, domyślam się ...GHCi ignoruje oznaczenie typu:

Prelude> let myprint = (putStrLn . show) :: Show x => x -> IO() 
Prelude> :t myprint 
myprint ::() -> IO() 

Co to za czarnoksięstwo? Jesteś bezzasadny ignorowanie mojej deklaracji typu ?! O_O

Czy jest jakiś sposób, w jaki mogę przekonać GHCi, aby zrobił to, co faktycznie zamierzałem?

+1

Dziki zgadnę: bał ograniczenie monomorfizm. – Jubobs

+0

@Jubobs To by było również moje przypuszczenie - z wyjątkiem tego, że nie podpisu jawnego typu nie można tego wyłączyć? – MathematicalOrchid

+1

Czy używasz starej wersji GHC? Jestem w wersji 7.8.3 i otrzymuję sygnaturę typu, której ogólnie się spodziewałeś ('Show a => a -> IO()'), nawet bez użycia wyrażenia podpisu. Uzyskanie '() -> IO()' wydaje się być rzeczywistym problemem z GHC. – MasterMastic

Odpowiedz

16

Możemy wykonać następujące czynności, z ograniczeniem monomorfizm na:

>let myprint :: Show x => x -> IO(); myprint = putStrLn . show 
>:t myprint 
myprint :: Show x => x -> IO() 

To nie jest taka sama jak let myprint = putStrLn . show :: Show x => x -> IO(). W pierwszym przypadku mamy wiązanie z podpisem typu, w drugim przypadku mamy wiązanie let z adnotacją typu wewnątrz prawej strony. Monomorfizm sprawdza sygnatury typów najwyższego poziomu, ale nie lokalne adnotacje.

+1

Zawsze polecam flagę ': set + m', która pozwala na wielowątkowe wprowadzanie danych w GHCi. Jest bardzo przydatny w takich przypadkach, chociaż żałuję, że GHCi nie miał inteligentnego wcięcia z wielowierszowym wejściem, takim jak IPython (chociaż projekt Jupyter pracuje nad naprawianiem tego) – bheklilr

21

Dodanie typu adnotacji do ekspresji jak w

e :: type 

sprawia czek kompilatora że e ma iż type, jak również wykorzystanie że type prowadzenia pojazdów zmiennych typu instancji i wybór instancji. Jednak, jeśli type jest polimorficzny, nadal można go utworzyć później. Rozważ np.

(id :: a -> a) "hello" 

Powyżej a zostanie instancja do String, pomimo mojego adnotacji. Ponadto

foo :: Int -> Int 
foo = (id :: a -> a) 

uczyni a do wystąpienia do Int później. Powyższa adnotacja id nie przekazuje żadnej informacji do GHC: już wie, że ten typ ma id. Możemy usunąć to bez wpływu na sprawdzanie typu. Oznacza to, że wyrażenia id i id :: a->a są nie tylko dynamicznie równoważne, ale również statycznie takie.

Podobnie wyrażenia

putStrLn . show 

i

(putStrLn . show) :: Show x => x -> IO() 

są statycznie równoważne: jesteśmy po prostu komentowania kod z typem GHC można wywnioskować. Innymi słowy, nie dostarczamy GHC żadnych informacji, o których jeszcze nie wie.

Po sprawdzeniu adnotacji typ GHC może następnie utworzyć egzemplarz x. Ograniczenie monomorfizmu robi to w twoim przykładzie. Aby temu zapobiec, należy użyć adnotacji dla wiążącego jesteś wprowadzające, nie dla ekspresji:

myprint :: Show x => x -> IO() 
myprint = (putStrLn . show)