Typ zur Darstellung einer Liste mit 0 bis 5 Werten
14
Ich habe eine Übung, in der ich einen Typ für die Darstellung einer Liste mit 0 bis 5 Werten definieren muss. Zuerst dachte ich, ich könnte das rekursiv so lösen:
data List a = Nil | Content a (List a)
Aber ich denke nicht, dass dies der richtige Ansatz ist. Können Sie mir bitte einen Denkanstoß geben?
Ich werde Ihre Übung nicht für Sie beantworten - für Übungen ist es besser, die Antwort selbst herauszufinden -, aber hier ist ein Hinweis, der Sie zur Antwort führen sollte: Sie können eine Liste mit 0 bis 2 Elementen als definieren
data List a = None | One a | Two a a
Überlegen Sie nun, wie Sie dies auf fünf Elemente erweitern können.
Nun, eine rekursive Lösung ist sicherlich die normale und in der Tat nette Sache in Haskell, aber es ist ein bisschen schwierig, die Anzahl der Elemente dann zu begrenzen. Betrachten Sie für eine einfache Lösung des Problems zunächst die dumme, aber funktionierende von Bradm.
Bei der rekursiven Lösung besteht der Trick darin, eine "Zähler" -Variable über die Rekursion zu übergeben und dann die Berücksichtigung weiterer Elemente zu deaktivieren, wenn Sie das maximal zulässige Maß erreichen. Dies kann gut mit einem GADT gemacht werden:
{-# LANGUAGE GADTs, DataKinds, KindSignatures, TypeInType, StandaloneDeriving #-}import Data.Kind
import GHC.TypeLits
infixr5:#data ListMax :: Nat -> Type -> Type where
Nil :: ListMax n a
(:#):: a -> ListMax n a -> ListMax (n+1) a
derivinginstance(Show a)=> Show (ListMax n a)
Dann
*Main>0:#1:#2:#Nil :: ListMax 5 Int
0:#(1:#(2:# Nil))*Main>0:#1:#2:#3:#4:#5:#6:#Nil :: ListMax 5 Int
<interactive>:13:16: error:• Couldn't match type‘1’ with ‘0’
Expected type: ListMax 0 Int
Actual type: ListMax (0+1) Int
• In the second argument of‘(:#)’, namely ‘5:#6:# Nil’
In the second argument of‘(:#)’, namely ‘4:#5:#6:# Nil’
In the second argument of‘(:#)’, namely ‘3:#4:#5:#6:# Nil’
Vielen Dank. Da es sich um eine Anfängerübung handelt, denke ich, dass dies der einfachere Ansatz ist. Aber ich werde auch über Ihren Ansatz nachdenken.
Mayerph
7
Lassen Sie mich der Vollständigkeit halber einen "hässlichen" alternativen Ansatz hinzufügen, der jedoch eher grundlegend ist.
Denken Sie daran, dass dies Maybe aein Typ ist, dessen Werte von der Form Nothingoder Just xfür einige sind x :: a.
Daher können wir durch Neuinterpretation der obigen Werte Maybe aeinen "eingeschränkten Listentyp" betrachten, bei dem Listen entweder null oder ein Element haben können.
Fügen Sie jetzt (a, Maybe a)einfach ein weiteres Element hinzu, sodass es sich um einen "Listentyp" handelt, bei dem Listen ein ( (x1, Nothing)) oder zwei ( (x1, Just x2)) Elemente enthalten können.
Daher Maybe (a, Maybe a)handelt es sich um einen "Listentyp", bei dem Listen null ( Nothing), eins ( Just (x1, Nothing)) oder zwei ( (Just (x1, Just x2)) Elemente enthalten können.
Sie sollten jetzt verstehen können, wie Sie vorgehen müssen. Lassen Sie mich noch einmal betonen, dass dies keine bequeme Lösung ist, aber es ist (IMO) eine schöne Übung, sie trotzdem zu verstehen.
Mit einigen erweiterten Funktionen von Haskell können wir das Obige mithilfe einer Typfamilie verallgemeinern:
type family List (n :: Nat)(a :: Type):: Type where
List 0 a =()
List n a = Maybe (a, List (n-1) a)
Diese Antwort könnte um die Typfamilie der Vielleicht-basierten Liste der maximalen Länge n erweitert werden .
Links um den
@leftaroundabout Fertig. Das mag für einen Anfänger etwas zu viel sein, aber ich habe es trotzdem hinzugefügt.
Chi
höchstens drei as in Either () (a, Either () (a, Either () (a, Either () ())))... interessanter Typalgebra , foldr (.) id (replicate 3 $ ([0] ++) . liftA2 (+) [1]) $ [0] == [0,1,2,3].
Lassen Sie mich der Vollständigkeit halber einen "hässlichen" alternativen Ansatz hinzufügen, der jedoch eher grundlegend ist.
Denken Sie daran, dass dies
Maybe a
ein Typ ist, dessen Werte von der FormNothing
oderJust x
für einige sindx :: a
.Daher können wir durch Neuinterpretation der obigen Werte
Maybe a
einen "eingeschränkten Listentyp" betrachten, bei dem Listen entweder null oder ein Element haben können.Fügen Sie jetzt
(a, Maybe a)
einfach ein weiteres Element hinzu, sodass es sich um einen "Listentyp" handelt, bei dem Listen ein ((x1, Nothing)
) oder zwei ((x1, Just x2)
) Elemente enthalten können.Daher
Maybe (a, Maybe a)
handelt es sich um einen "Listentyp", bei dem Listen null (Nothing
), eins (Just (x1, Nothing)
) oder zwei ((Just (x1, Just x2)
) Elemente enthalten können.Sie sollten jetzt verstehen können, wie Sie vorgehen müssen. Lassen Sie mich noch einmal betonen, dass dies keine bequeme Lösung ist, aber es ist (IMO) eine schöne Übung, sie trotzdem zu verstehen.
Mit einigen erweiterten Funktionen von Haskell können wir das Obige mithilfe einer Typfamilie verallgemeinern:
quelle
a
s inEither () (a, Either () (a, Either () (a, Either () ())))
... interessanter Typalgebra ,foldr (.) id (replicate 3 $ ([0] ++) . liftA2 (+) [1]) $ [0] == [0,1,2,3]
.