Sök…


Anmärkningar

En av styrkorna med Haskell är förmågan att utnyttja typsystemet för att modellera delar av ditt problemdomän i typsystemet. Då möter man ofta mycket komplexa typer. När man skriver program med dessa typer (dvs med värden som har dessa typer) blir det ibland nästan obehagligt att ”jonglera” alla typerna. Från GHC 7.8 finns det en ny syntaktisk funktion som kallas typhål. Typade hål förändrar inte semantiken i kärnspråket; de är avsedda enbart som ett hjälpmedel för att skriva program.

För en fördjupad förklaring av skrivade hål, samt en diskussion om utformningen av typade hål, se Haskell wiki .


Avsnitt i GHC användarhandbok om typade hål .

Syntax för typade hål

Ett typat hål är ett enda understreck ( _ ) eller en giltig Haskell-identifierare som inte är inom räckvidd, i ett uttryckssammanhang. Innan typ av hål existerar skulle båda dessa saker utlösa ett fel, så att den nya syntaxen inte stör någon gammal syntax.

Kontrollera beteende hos typade hål

Standardbeteendet för typade hål är att producera ett kompileringstidsfel när du stöter på ett typat hål. Det finns dock flera flaggor för att finjustera deras beteende. Dessa flaggor sammanfattas enligt följande ( GHC trac ):

Som standard har GHC skrivhål aktiverat och producerar ett kompileringsfel när det möter ett typat hål.

När -fdefer-type-errors eller -fdefer-typed-holes -fdefer-type-errors -fdefer-typed-holes är aktiverat konverteras hålfel till varningar och resulterar i körtidsfel vid utvärdering.

Varningsflaggan -fwarn-typed-holes är som standard på. Utan -fdefer-type-errors eller-- -fdefer-typed-holes denna flagga en no-op, eftersom skrivade hål är ett fel under dessa förhållanden. Om någon av uppskjutningsflaggorna är aktiverade (omvandla fel i -fno-warn-typed-holes till varningar) -fno-warn-typed-holes typhål varningarna. Detta innebär att sammanställningen lyckas tyst och att utvärdering av ett hål ger ett körtidfel.

Semantik av typhål

Värdet på ett typhål kan helt enkelt sägas vara undefined , även om ett typat hål utlöser ett kompileringstidsfel, så det är inte strikt nödvändigt att tilldela det ett värde. Emellertid producerar ett typat hål (när de är aktiverade) ett kompileringstidsfel (eller varning med uppskjutna typfel) som anger namnet på det typade hålet, dess utdragna mest allmänna typ och typerna av lokala bindningar. Till exempel:

Prelude> \x -> _var + length (drop 1 x)

<interactive>:19:7: Warning:
    Found hole `_var' with type: Int
    Relevant bindings include
      x :: [a] (bound at <interactive>:19:2)
      it :: [a] -> Int (bound at <interactive>:19:1)
    In the first argument of `(+)', namely `_var'
    In the expression: _var + length (drop 1 x)
    In the expression: \ x -> _var + length (drop 1 x)

Observera att när det gäller typade hål i uttryck som matats in i GHCi-svaret (som ovan) rapporterades också typen av uttryckt in som it (här av typen [a] -> Int ).

Använd typ av hål för att definiera en klassinstans

Typade hål kan göra det enklare att definiera funktioner genom en interaktiv process.

Säg att du vill definiera en klassinstans Foo Bar (för din anpassade Bar typ för att använda den med någon polymorfisk biblioteksfunktion som kräver en Foo instans). Du skulle nu traditionellt leta upp Foo dokumentationen, ta reda på vilka metoder du behöver definiera, granska deras typer etc. - men med skrivna hål kan du faktiskt hoppa över det!

Definiera först en dummy-instans:

instance Foo Bar where

Kompilatorn kommer nu att klaga

Bar.hs:13:10: Warning:
No explicit implementation for
  ‘foom’ and ‘quun’
In the instance declaration for ‘Foo Bar’

Okej, så vi måste definiera foom för Bar . Men vad är det även tänkt att vara? Återigen är vi för lata för att titta i dokumentationen och fråga bara kompilatorn:

instance Foo Bar where
  foom = _

Här har vi använt ett typat hål som en enkel "dokumentationsfråga". Kompilatorns utgångar

Bar.hs:14:10:
    Found hole ‘_’ with type: Bar -> Gronk Bar
    Relevant bindings include
      foom :: Bar -> Gronk Bar (bound at Foo.hs:4:28)
    In the expression: _
    In an equation for ‘foom’: foom = _
    In the instance declaration for ‘Foo Bar’

Lägg märke till hur kompilatorn redan har fyllt klassvariabeln med betongtypen Bar som vi vill instansera den för. Detta kan göra signaturen mycket lättare att förstå än den polymorfa som finns i klassdokumentationen, särskilt om du har att göra med en mer komplicerad metod för t.ex. en klass med flera parametrar.

Men vad fan är Gronk ? Just nu är det förmodligen en bra idé att fråga Hayoo . Men vi kan fortfarande komma undan utan detta: som en blind gissning antar vi att detta inte bara är en typkonstruktör utan också konstruktören med ett enda värde, dvs att den kan användas som en funktion som på något sätt kommer att ge ett Gronk a värde. Så vi försöker

instance Foo Bar where
  foom bar = _ Gronk

Om vi har tur är Gronk faktiskt ett värde, och kompilatorn kommer nu att säga

    Found hole ‘_’
      with type: (Int -> [(Int, b0)] -> Gronk b0) -> Gronk Bar
    Where: ‘b0’ is an ambiguous type variable

Okej, det är fult - först Gronk bara notera att Gronk har två argument, så vi kan förfina vårt försök:

instance Foo Bar where
  foom bar = Gronk _ _

Och det här är ganska tydligt:

    Found hole ‘_’ with type: [(Int, Bar)]
    Relevant bindings include
      bar :: Bar (bound at Bar.hs:14:29)
      foom :: Bar -> Gronk Bar (bound at Foo.hs:15:24)
    In the second argument of ‘Gronk’, namely ‘_’
    In the expression: Gronk _ _
    In an equation for ‘foom’: foom bar = Gronk _ _

Du kan nu göra ytterligare framsteg genom att t.ex. dekonstruera bar (komponenterna kommer då att visas, med typer, i avsnittet Relevant bindings ). Ofta är det vid någon tidpunkt helt uppenbart vad den rätta definitionen kommer att vara, för du ser alla tillgängliga argument och typerna passar ihop som ett pussel. Eller alternativt kan du se att definitionen är omöjlig och varför.

Allt detta fungerar bäst i en redaktör med interaktiv sammanställning, t.ex. Emacs med haskell-läge. Du kan sedan använda typade hål ungefär som mus-över-värde-frågor i en IDE för ett tolkat dynamiskt imperativspråk, men utan alla begränsningar.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow