2015-10-11 23 views
6

Próbowałem zrobić następującą definicję funkcję:Dlaczego ta punktowa definicja nie działa w Haskell?

relativelyPrime x y = gcd x y == 1 

punkt bezpłatny:

relativelyPrime = (== 1) . gcd 

Jednak to daje mi następujący błąd:

Couldn't match type ‘Bool’ with ‘a -> Bool’ 
Expected type: (a -> a) -> a -> Bool 
    Actual type: (a -> a) -> Bool 
Relevant bindings include 
    relativelyPrime :: a -> a -> Bool (bound at 1.hs:20:1) 
In the first argument of ‘(.)’, namely ‘(== 1)’ 
In the expression: (== 1) . gcd 
In an equation for ‘relativelyPrime’: 
    relativelyPrime = (== 1) . gcd 

nie mam dość Rozumiesz. gcd pobiera dwa Ints/Integer, zwraca jeden Ints/Integer, a następnie jeden Int/Integer jest sprawdzany pod kątem równości '1'. Nie widzę, gdzie jest mój błąd.

+4

dobrze 'gcd' będzie produkować inną funkcję, jeśli podano tylko jeden argument - w punkt-a darmowa wersja przekazujesz tę * funkcję * do '(== 1)', która oczywiście nie wie, jak obsługiwać funkcje;) – Carsten

+2

może rozumiesz, kiedy po raz pierwszy * usuniesz * jeden * punkt *: 'relativePrime x = (= = 1). gcd x' to działa!Teraz nie możesz * usunąć * 'x', ponieważ jest * przywiązany * do szybkiego do' gcd' - mógłbyś, gdybyś miał '(== 1) $ gcd x' – Carsten

+1

@ Komentarz Carstena jest poprawny. Jedną opcją byłoby użycie 'uncurry', aby zamienić' gcd' w funkcję pojedynczego argumentu (biorąc krotkę dwóch liczb całkowitych). – psmears

Odpowiedz

7

To nie działa, ponieważ gcd wymaga dwóch wejść, podczas gdy skład funkcji zapewnia tylko jedno wejście: gcd. Rozważmy definicję złożenie funkcji:

f . g = \x -> f (g x) 

Stąd wyrażenie (== 1) . gcd odpowiada:

\x -> (== 1) (gcd x) 

To nie jest to, co chcesz. Chcesz:

\x y -> (== 1) (gcd x y) 

Można zdefiniować nowy operator komponować jednoskładnikowa funkcję z funkcją binarną:

f .: g = \x y -> f (g x y) 

Następnie Twój wyraz staje:

relativelyPrime = (== 1) .: gcd 

W rzeczywistości, (.:) Operator można zdefiniować pod względem składu funkcji:

(.:) = (.) . (.) 

Wygląda trochę jak sowa, ale w rzeczywistości są one równoważne. Tak więc kolejny sposób napisać wyrażenie:

relativelyPrime = ((== 1) .) . gcd 

Jeśli chcesz zrozumieć, co się dzieje potem patrz: What does (f .) . g mean in Haskell?

5

jak skomentował to - jeśli naprawdę chcesz punkt wolna wersję można najpierw skorzystać uncurry gcd przekształcić gcd do wersji, która przyjmuje jedno wejście (krotka):

Prelude> :t uncurry gcd 
uncurry gcd :: Integral c => (c, c) -> c 

następnie skontaktować się z (== 1) i wreszcie curry go ponownie do oryginalnego podpisu:

relativeelyPrime = curry ((== 1) . (uncurry gcd)) 

wersja nie działa tylko dlatego gcd wywołuje funkcję, jeśli podano tylko pierwszy argument i to nie jest żaden legalny wkład dla (== 1), który czeka na numer.

Powiązane problemy