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.