2011-09-13 15 views
73

Patrząc przez Prelude Haskell, ja see a functionconst:Jaki jest sens "const" w Preludium Haskella?

const x _ = x 

mogę nie wydaje się znaleźć coś odpowiedniego dotyczące tej funkcji.

O co ci chodzi? Czy ktoś może podać przykład miejsca, w którym można skorzystać z tej funkcji?

+5

Przykład: 'backgroundColor :: Text -> Color' jest dla mnie' backgroundColor = const White' – Zhen

Odpowiedz

68

Przydaje się do przekazywania funkcji wyższego rzędu, gdy nie potrzebujesz całej ich elastyczności. Na przykład, monadycznego operator sekwencja >> mogą być definiowane w kategoriach monadycznej operatora wiążą jako

x >> y = x >>= const y 

To nieco schludniej niż przy użyciu lambda

x >> y = x >>= \_ -> y 

i można nawet używać go wskazać wolne

(>>) = (. const) . (>>=) 

chociaż nie polecam tego w tym przypadku szczególnie.

+8

+1. Często pojawia się również podczas używania kombinatorów parserów. –

+37

Ahh, więc jest to bardziej "generator funkcji" - używam go z jednym argumentem i daje mi funkcję (przyjmując jeden argument), który zawsze zwraca stałą wartość. Zatem 'map (const 42) [1..5]' daje '[42, 42, 42, 42, 42]'. – stusmith

+2

stusmith: Masz to. 'const' jest użyteczne do zastosowania do pojedynczego argumentu, aby uzyskać funkcję, w której jedna jest potrzebna (np. przekazanie do' mapy'). – Conal

24

Aby dodać doskonałą odpowiedzią bezpośrednią hammar za: funkcje pokorne jak const i id są bardzo przydatne w funkcji wyższego rzędu z tego samego powodu, że są one podstawowym w SKI combinator calculus.

Nie sądzę, że funkcje preludium haskell zostały zamodelowane świadomie po tym systemie formalnym lub czymkolwiek. Po prostu tworzenie bogatych abstrakcji w haskell jest bardzo łatwe, więc często widzimy, że te typy teoretycznych rzeczy wydają się praktycznie użyteczne.

wtyczka Shameless, ale na blogu o tym, jak instancja aplikacyjnych dla (->) są rzeczywiście S i K kombinatorów here, jeśli o takie rzeczy jesteś w.

+7

Cóż, kombinatory SKI z pewnością wpłynęły na Preludium. Pamiętam, że kłóciłem się z Joe Faselem, czy kombinator S powinien być włączony, czy nie. – augustss

+4

Nawiasem mówiąc, '((->) e)' jest także monadą czytelnika - z 'Reader' i tym podobnymi po prostu jest' wrapperami newtype '- a funkcja 'ask' jest wtedy' id', więc to jest '. Ja także kombinator. Jeśli zamiast tego spojrzysz na oryginalną podstawę BCKW Haskella Curry, 'B',' K' i 'W' to odpowiednio' fmap', 'return' i' join'. –

+1

Link do bloga w odpowiedzi jest martwy. Powinno teraz wskazywać tutaj: http://brandon.si/code/do-aplikator-funktory-przyprogramuj-tak-s-k-combinators/ – nsxt

19

Prostym przykładem użycia const jest. Dzięki tej funkcji możesz powiedzieć: Mam tu funktora z czymś nudnym, ale zamiast tego chcę mieć w sobie tę inną interesującą rzecz, bez zmiany kształtu funktora. Na przykład.

import Data.Functor 

42 <$ Just "boring" 
--> Just 42 

42 <$ Nothing 
--> Nothing 

"cool" <$ ["nonsense","stupid","uninteresting"] 
--> ["cool","cool","cool"] 

Definicja brzmi:

(<$) :: a -> f b -> f a 
(<$) = fmap . const 

lub napisany nie tak bezcelowe:

cool <$ uncool = fmap (const cool) uncool 

Zobaczysz jak const stosuje się tu do "zapomnieć" o wejściu.

11

Innym zastosowaniem jest implementacja funkcji składowych klasy, które mają fałszywy argument, który nie powinien być oceniany (używany do rozstrzygania niejednoznacznych typów). Przykład, który może być w Data.bits:

instance Bits Int where 
    isSigned = const True 
    bitSize = const wordSize 
    ... 

Używając const mówimy wyraźnie, że definiujemy stałe wartości.

Osobiście nie lubię używania fałszywych parametrów, ale jeśli są one używane w klasie, jest to raczej niezły sposób pisania instancji.

13

Nie mogę znaleźć niczego istotnego w odniesieniu do tej funkcji.

Wiele innych odpowiedzi dotyczy względnie ezoterycznych (przynajmniej dla nowoprzybyłych) aplikacji const. Oto prosty: możesz użyć const, aby pozbyć się lambda, która przyjmuje dwa argumenty, odrzuca pierwszy, ale robi coś interesującego z drugim.

Na przykład, następujący (nieefektywne!) Realizacja length,

length' = foldr (\_ acc -> 1 + acc) 0 

może być zapisane jako

length' = foldr (const (1+)) 0 

która jest być może bardziej elegancki.

Wyrażenie jest rzeczywiście równoważne \_ acc -> 1 + acc, ponieważ pobiera jeden argument, odrzuca go i zwraca sekcję (1+).

+2

Zajęło mi to 5 minut, aby zrozumieć, jak to działa :) –

1

const może być tylko implementacją, której szukasz w połączeniu z innymi funkcjami. Oto przykład, który odkryłem.

Powiedzmy, że chcemy przepisać strukturę 2-tek na inną strukturę 2-tek. Mogę wyrazić to jako tak:

((a,b),(c,d)) ⇒ (a,(c,(5,a))) 

mogę dać prosta definicja z pasującymi Wzór:

f ((a,b),(c,d)) = (a,(c,(5,a))) 

Co jeśli chcę bezcelowe (milczącej) rozwiązanie dla tego rodzaju przepisuje? Niektóre myślenie i manipulowanie później, odpowiedź brzmi, że możemy wyrazić wszelkie przeróbki z (&&&), const, (.), fst, snd. Zauważ, że (&&&) pochodzi z Control.Arrow.

Roztwór przykład przy użyciu tych funkcji:

(fst.fst &&& (fst.snd &&& (const 5 &&& fst.fst))) 

Uwaga Podobieństwo (a,(c,(5,a))). Co się stanie, jeśli zmienimy &&& na ? Następnie czytamy:

(fst.fst, (fst.snd, (const 5, fst.fst))) 

Wskazówki jak a jest pierwszym elementem pierwszego elementu, a to, co fst.fst projekty. Zauważ, że c jest pierwszym elementem drugiego elementu, i to jest to, co projektuje fst.snd. Oznacza to, że zmienne stają się ścieżką do ich źródła.

pozwala nam wprowadzić stałe. Interesujące, jak nazwa pasuje do znaczenia!

Potem uogólnić ten pomysł z aplikacyjnych, dzięki czemu można napisać dowolną funkcję w bezcelowym stylu (tak długo, jak masz analiza case dostępne funkcje, takie jak maybe, either, bool). Ponownie, const odgrywa rolę wprowadzania stałych. Możesz zobaczyć tę pracę w pakiecie Data.Function.Tacit.

Kiedy zaczynasz abstrakcyjnie, cel, a następnie pracujesz nad wdrożeniem, możesz być zaskoczony odpowiedziami Oznacza to, że każda funkcja może być tak tajemnicza, jak każde jedno ząb w maszynie. Jeśli jednak cofniesz się, aby pokazać całą maszynę, możesz zrozumieć kontekst, w którym to pokrętło jest konieczne.