2015-01-02 13 views
5

Oglądam samouczek dotyczący analizatorów składni w haskell https://www.youtube.com/watch?v=9FGThag0Fqs. Wykład rozpoczyna się od zdefiniowania kilku naprawdę podstawowych analizatorów składni. Są one używane razem, aby później tworzyć bardziej skomplikowane parsery. Jednym z podstawowych parserów jest pozycja. Służy do wyodrębnienia znaku z analizowanego łańcucha.Dlaczego używać lambda zamiast dopasowywania wzorców?

Wszystkie Parsery mają następujący typ:

type Parser a = String -> [(a, String)]           

Parser poz jest zdefiniowany następująco:

item :: Parser Char                
item = \inp -> case inp of              
        [] -> []             
        (x:xs) -> [(x,xs)] 

nie jestem tak przyzwyczajony do tej składni, tak to wygląda dla mnie dziwne . Ja napisałem go:

item' :: Parser Char                
item' [] = []                 
item' (x:xs) = [(x,xs)] 

Badanie to wskazuje, że w ghci są równe:

*Main> item "" 
[] 
*Main> item "abc" 
[('a',"bc")] 
*Main> item' "" 
[] 
*Main> item' "abc" 
[('a',"bc")] 

Wykładowca sprawia krótki komentarz na temat myślenia wygląda jaśniej, ale nie zgadzam się. Więc moje pytania są następujące:

Czy rzeczywiście są całkowicie identyczne? Dlaczego wersja lambda jest bardziej przejrzysta?

+2

Powiedziałbym, że to kwestia gustu. – augustss

Odpowiedz

11

Wierzę, że to pochodzi z powszechną praktyką pisania

f :: Type1 -> ... -> Typen -> Result 
f x1 ... xn = someResult 

gdzie mamy dokładnie n strzałek funkcji w rodzaju, a dokładnie n argumenty po lewej stronie równania. Ułatwia to powiązanie typów i parametrów formalnych.

Jeśli Result jest alias typu do funkcji, może napisać

f :: Type1 -> ... -> Typen -> Result 
f x1 ... xn y = something 

lub

f :: Type1 -> ... -> Typen -> Result 
f x1 ... xn = \y -> something 

To ostatnie wynika z konwencją powyżej: n strzałek n zmienne po stronie lewej . Również po prawej stronie mamy coś w rodzaju Result, dzięki czemu łatwiej je zauważyć. Ten pierwszy zamiast tego nie istnieje i można pominąć dodatkowy argument podczas szybkiego czytania kodu.

Ponadto, ten styl sprawia, że ​​łatwo przekonwertować Result do newtype zamiast typu alias:

newtype Result = R (... -> ...) 

f :: Type1 -> ... -> Typen -> Result 
f x1 ... xn = R $ \y -> something 

Oddelegowany kod item :: Parser Char jest przykładem tego stylu kiedy n=0.

+2

Jestem w pełni zgodna co do nowości. Będziesz chciał, aby twój parser był co najmniej Funktorem i Aplikacją, więc będziesz potrzebować nowego typu, więc przygotowanie go do tego przy minimalnej edycji jest dobrą rzeczą. – AndrewC

3

Myślę, że są absolutnie równi. Definicja typu lambda umieszcza nazwę item na anonimowej funkcji lambda, która dopasowuje wzorce do wnętrza. Definicja stylu dopasowywania wzorca definiuje je bezpośrednio. Ale w końcu obie są funkcjami dopasowywania wzorców. Myślę, że to kwestia osobistego gustu.

Również definicja lambda stylu mogłaby zostać uznana w pointfree stylu, czyli funkcja zdefiniowana bez wyraźnego spisując swoje argumenty faktycznie nie jest bardzo dużo pointfree ponieważ argument jest jeszcze napisane (ale w innym miejsce), ale w tym przypadku nic nie dostaniesz.

Oto kolejny możliwy definion, gdzieś pośrodku tych dwóch:

item :: Parser Char 
item inp = case inp of 
       [] -> [] 
       (x:xs) -> [(x, xs)] 

To w zasadzie identyczny z lambda-stylu, ale nie pointfree.

+0

To w ogóle nie jest bez sensu. W '\ y -> ...', argument o nazwie "y" jest "punktem". To, że nie znajduje się po lewej stronie '=', nie sprawia, że ​​ta definicja jest wolna od punktu. – amalloy

+0

@amalloy Masz prawdopodobnie rację (teraz edytuję swoją odpowiedź). Ale czy nie jest to bardziej bezprzedmiotowe niż bezpośrednia definicja? :) – zegkljan

4

Dlaczego należy unikać definicje funkcji equational (by Roman Cheplyaka): http://ro-che.info/articles/2014-05-09-clauses

Główne Punkty z powyższym linkiem:

  • DRY: funkcyjne i argumentów nazwy są powtarzane -> trudniej byłaby
  • Bardziej przejrzysty pokazuje, które argumenty funkcja decyduje o
  • Łatwo dodać pragmy (np. Do profilowania)
  • Syntaktycznie bliżej niższego poziomu kodu

To jednak nie wyjaśnia lambda ..

+0

@bheklilr Dodałem listę – rethab

Powiązane problemy