2012-07-19 11 views
7

Ciągle słyszę dużo o programowaniu bez punktów i postanowiłem zrobić mały eksperyment, aby przetestować moje zrozumienie tego. Wymagało to zaostrzenia funkcji liczbowej i przekształcenia jej w formę wolną od punktów. Udało mi się to zrobić, ale wynik wolny od punktu jest dużo mniej czytelny niż wynik ostry.Notacja punktowa, rekursja i dopasowywanie wzorów

-- pointed 
fact 0 = 1 
fact n = n * (fact (n-1)) 
-- point free 
fact' = foldr1 (*) . takeWhile ((<) 0) . iterate (flip (-) 1) 

Czy brakuje mi czegoś, co jest niezbędne do wycelowania w notację wolną czy jest to tak czytelne, jak pewne przekształcenia? Wydaje mi się, że dużą częścią funkcji fact jest dopasowanie wzorca na zero, a nawet dopasowanie wzorca jest jednym z największych powodów, dla których kocham Haskella. Jednak notacja wolna od punktów wydaje się zupełnie nie pozwalać na to, podobnie jak niektóre inne rzeczy, które są niezwykle użyteczne, jak na przykład listy.

+6

wolę 'produkt. enumFromTo 1'. – Vitus

+5

[Ewolucja programisty Haskella] (http://www.willamette.edu/~fruehr/haskell/evolution.html) – sdcvvc

+2

Czekaj. Oczekiwano _readability_ od _point-free syntax_? Ha. Ha ha. Hahahahaha. Nie. –

Odpowiedz

15

Kanoniczna silnia w formie pointfree jest:

fact = product . enumFromTo 1 

(co stanowi równowartość fact n = product [1..n])

Uważam, że jest to dość czytelne. Jednak zgodzę się, że oryginalna wersja:

fact 0 = 1 
fact n = n * (fact (n-1)) 

Bardzo dobrze pasuje do definicji i jest również czytelna.

Punkt (ha!) Postaci bezfunktowej ma ułatwić rozumowanie funkcji jako składu innych funkcji. Jednakże funkcja silni nie jest tak naprawdę doskonałym kandydatem do tego rodzaju rozumowania.

Decyzja jest oczywiście twoja.

+0

Interesujące, nie wiedziałem, że istnieje funkcja typu enumFromTo. A co z dopasowaniem wzorców? Z konieczności wymaga to wskazanego zapisu. Czy uważasz, że to nie podlega rozumowaniu o funkcjach jako kompozycji? – Dwilson

+0

@Dwilson: jest częścią pakietu 'Enum' typeclass: http: //hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html # t: Enum –

+3

@Dwilson: Możesz tłumaczyć dopasowywanie wzorca na notację wolną od punktów. Wystarczy spojrzeć na funkcje takie jak "maybe" lub "either"; biorąc "albo" jako przykład: dajesz mu dwie funkcje, jedną dla "Left" i drugą dla "Right" i to wszystko. W rzeczywistości można dość łatwo skonstruować te funkcje, ponieważ są one częścią izomorfizmu między ADT a jego kodowaniem przez Kościół. Listy prawdopodobnie nie mają takiej funkcji, ale są łatwe do wdrożenia: 'listcase [] z f = z; listoteka (x: xs) z f = f x xs'. – Vitus

2

Dla każdego typu danych unii algebraicznej powinna istnieć funkcja dyskryminatora typu, która zawiera wzór pasujący do tego typu. Mamy już

either :: (a -> c) -> (b -> c) -> Either a b -> c 
maybe :: b -> (a -> b) -> Maybe a -> b 

Podobnie musi być taka funkcja dla numerów,

num :: (Num a) => b -> (a -> b) -> a -> b 
num z nz 0 = z 
num z nz x = nz x 

więc możemy napisać

import Control.Applicative 
import Data.Function 

fact :: (Num a) => a -> a 
fact x = num 1 (\x-> (*) (fact (pred x)) x) x 
     = num 1 ((*) =<< (fact.pred)) x 

tj

fact = (num 1 . ((*) =<<) . (. pred)) fact 
     = fix (num 1 . ((*) =<<) . (. pred)) 
+1

Heck, teraz jest _much_ bardziej czytelny niż "produkt. enumFromTo 1' ... – leftaroundabout

+1

@leftaround był tam ':)' gdzieś może? .... :) Głównym punktem, który chciałem zrobić, była funkcja 'num'. ale także, aby dokładniej odpowiedzieć na tytuł - nie chodzi o "czynnik" per se ... –

+0

Choć z pewnością mniej czytelny, jest to interesujące. Czy mógłbyś trochę więcej rozwinąć w pierwszym zdaniu, a co "num" oznacza w odniesieniu do tego, W szczególności część funkcji dyskryminatora typu? – Dwilson