2015-04-23 8 views
9

Ich versuche, einen Typ für Listen fester Länge in Haskell zu definieren. Wenn ich den Standardweg nutze, um natürliche Zahlen als unäre Typen zu kodieren, funktioniert alles gut. Wenn ich jedoch versuche, alles auf GHC-Typ-Literalen aufzubauen, stoße ich auf viele Probleme.Listen von Literalen fester Länge und Typ

Mein erster Schuss auf den Typ gewünschte Liste war

data List (n :: Nat) a where 
    Nil :: List 0 a 
    (:>) :: a -> List n a -> List (n+1) a 

die leider nicht zum Schreiben einer Zip-Funktion mit Typ

zip :: List n a -> List n b -> List n (a,b) 

zuließ ich durch Subtrahieren von 1 von der Lösung dieses Problems könnte Typ Variable n in der Art von (:>):

data List (n :: Nat) a where 
    Nil :: List 0 a 
    (:>) :: a -> List (n-1) a -> List n a -- subtracted 1 from both n's 

Als nächstes habe ich versucht, eine Append-Funktion zu definieren:

append :: List n1 a -> List n2 a -> List (n1 + n2) a 
append Nil  ys = ys 
append (x :> xs) ys = x :> (append xs ys) 

Leider GHC sagt mir

Couldn't match type ‘(n1 + n2) - 1’ with ‘(n1 - 1) + n2’ 

Hinzufügen der Einschränkung ((n1 + n2) - 1) ~ ((n1 - 1) + n2) zur Unterzeichnung löst nicht die Probleme, da GHC

klagt
Could not deduce ((((n1 - 1) - 1) + n2) ~ (((n1 + n2) - 1) - 1)) 
from the context (((n1 + n2) - 1) ~ ((n1 - 1) + n2)) 

Jetzt bin ich offensichtlich in einer Art Endlosschleife gefangen.

Also ich würde gerne wissen, ob es möglich ist, einen Typ für Listen fester Länge mit Hilfe von Typ Literalen überhaupt zu definieren. Habe ich vielleicht sogar genau zu diesem Zweck eine Bibliothek beaufsichtigt? Im Grunde ist die einzige Voraussetzung, dass ich etwas wie List 3 a anstelle von schreiben möchte.

+0

Sie können einige Diskussion über die Fragen im Zusammenhang finden Vektorlängen eingeben Ebene im Hasochism Papier: https://personal.cis.strath.ac.uk/conor.mcbride/pub/hasochism. pdf – chi

+1

"Hasochismus" klingt sehr verlockend. Ich werde es dennoch versuchen. Vielen Dank. –

+0

Es ist wahrscheinlich einfacher, einen Wrapper für den neuen Typ um eine normale Liste mit einem 'Nat' zu erstellen, ähnlich wie bei' Linear.V'. Sie können einige Primitive in einem Modul definieren und den Konstruktor ausblenden, um alles sicher zu machen. – cchalmers

Antwort

19

Dies ist nicht wirklich eine Antwort.

https://hackage.haskell.org/package/ghc-typelits-natnormalise-0.2 Mit dieser

{-# LANGUAGE GADTs #-} 
{-# LANGUAGE TypeOperators #-} 
{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE KindSignatures #-} 
{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-} 

import GHC.TypeLits 

data List (n :: Nat) a where 
    Nil :: List 0 a 
    (:>) :: a -> List n a -> List (n+1) a 

append :: List n1 a -> List n2 a -> List (n1 + n2) a 
append Nil  ys = ys 
append (x :> xs) ys = x :> (append xs ys) 

... kompiliert, so offensichtlich richtig es ist.

???

+2

Ausgezeichneter Fund. –

+0

Ich wusste überhaupt nichts über Plugins für den Type Checker, aber das funktioniert wirklich gut. Vielen Dank. –

6

Typ-Level-Nummern-Literale haben noch keine Struktur, auf der wir Induktion durchführen können, und der eingebaute Constraint-Solver kann nur die einfachsten Fälle herausfinden. Momentan ist es besser, mit Peano Naturals zu bleiben.

Allerdings können wir die Literale immer noch als syntaktischen Zucker verwenden.

{-# LANGUAGE 
    UndecidableInstances, 
    DataKinds, TypeOperators, TypeFamilies #-} 

import qualified GHC.TypeLits as Lit 

data Nat = Z | S Nat 

type family Lit n where 
    Lit 0 = Z 
    Lit n = S (Lit (n Lit.- 1)) 

Jetzt können Sie List (Lit 3) a statt schreiben.

+0

Ich hatte auch eine ähnliche Idee, aber die Verwendung von "UndecidableInstances" macht mir immer ein bisschen Angst. Mit einem anderen Typ-Synonym könnte ich dann sogar zu "List 3 a" kommen. –

+0

Hier endet offensichtlich die Typfamilie, also gibt es kein Problem mit "UndecidableInstances". Selbst im allgemeinen Fall finde ich es nicht wirklich beängstigend. Wenn wir versehentlich abweichenden Code auf Typenebene schreiben, erhalten wir fast immer einen Grenzwert für die Kontexttiefe. Es ist sehr selten, dass wir tatsächlich GHC-Schleife bekommen können, und wir können dieses Problem mit einem Ctr-c leicht beheben. –

Verwandte Themen