digitare per rappresentare un elenco con valori da 0 a 5


14

Ho un esercizio in cui devo definire un tipo per rappresentare un elenco con valori da 0 a 5. Per prima cosa ho pensato di poterlo risolvere in modo ricorsivo in questo modo:

data List a = Nil | Content a (List a)

Ma non penso che questo sia l'approccio corretto. Potete per favore darmi un alimento di pensiero.

Risposte:


12

Non risponderò al tuo esercizio per te - per gli esercizi, è meglio capire tu stesso la risposta - ma ecco un suggerimento che dovrebbe portarti alla risposta: puoi definire un elenco con 0 o 2 elementi come

data List a = None | One a | Two a a

Ora, pensa a come estenderlo a cinque elementi.


10

Bene, una soluzione ricorsiva è certamente la cosa normale e di fatto bella in Haskell, ma è un po 'complicato limitare il numero di elementi allora. Quindi, per una semplice soluzione al problema, considera innanzitutto quello stupido ma funzionante di bradm.

Con la soluzione ricorsiva, il trucco è passare una variabile "counter" lungo la ricorsione e quindi disabilitare il consumo di più elementi quando si raggiunge il massimo consentito. Questo può essere fatto bene con un GADT:

{-# LANGUAGE GADTs, DataKinds, KindSignatures, TypeInType, StandaloneDeriving #-}

import Data.Kind
import GHC.TypeLits

infixr 5 :#
data ListMax :: Nat -> Type -> Type where
  Nil :: ListMax n a
  (:#) :: a -> ListMax n a -> ListMax (n+1) a

deriving instance (Show a) => Show (ListMax n a)

Poi

*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

molte grazie. Perché è un esercizio per principianti, penso che sia l'approccio più semplice. Ma penserò anche al tuo approccio.
Mayerph

7

Per completezza, vorrei aggiungere un approccio "brutto" alternativo, che è comunque piuttosto basilare.

Ricordiamo che Maybe aè un tipo i cui valori sono del modulo Nothingo Just xper alcuni x :: a.

Quindi, reinterpretando i valori sopra, possiamo considerare Maybe aun "tipo di elenco limitato" in cui gli elenchi possono avere zero o un elemento.

Ora (a, Maybe a)aggiunge semplicemente un altro elemento, quindi è un "tipo di elenco" in cui gli elenchi possono avere uno ( (x1, Nothing)) o due ( (x1, Just x2)) elementi.

Pertanto, Maybe (a, Maybe a)è un "tipo di elenco" in cui gli elenchi possono avere zero ( Nothing), uno ( Just (x1, Nothing)) o due ( (Just (x1, Just x2)) elementi.

Ora dovresti essere in grado di capire come procedere. Vorrei sottolineare ancora una volta che questa non è una soluzione conveniente da usare, ma è (IMO) un buon esercizio per capirlo comunque.


Utilizzando alcune funzionalità avanzate di Haskell, possiamo generalizzare quanto sopra usando una famiglia di tipi:

type family List (n :: Nat) (a :: Type) :: Type where
    List 0 a = ()
    List n a = Maybe (a, List (n-1) a)

Questa risposta potrebbe essere estesa con la famiglia di tipi dell'elenco forse basato sulla lunghezza massima n .
lasciato circa il

@leftaroundabout Fatto. Potrebbe essere un po 'troppo per un principiante, ma l'ho aggiunto comunque.
chi

al massimo tre as in Either () (a, Either () (a, Either () (a, Either () ())))... tipo interessante algebra, foldr (.) id (replicate 3 $ ([0] ++) . liftA2 (+) [1]) $ [0] == [0,1,2,3].
Will Ness,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.