digite para representar uma lista com 0 a 5 valores

14

Eu tenho um exercício em que tenho que definir um tipo para representar uma lista com 0 a 5 valores. Primeiro, pensei que poderia resolver isso recursivamente assim:

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

Mas não acho que essa seja a abordagem correta. Você pode, por favor, me dar um pensamento?

Mayerph
fonte

Respostas:

12

Não responderei seu exercício para você - para exercícios, é melhor descobrir a resposta você mesmo - mas aqui está uma dica que deve levá-lo à resposta: você pode definir uma lista com 0 a 2 elementos como

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

Agora, pense em como você pode estender isso para cinco elementos.

bradrn
fonte
10

Bem, uma solução recursiva é certamente a coisa normal e de fato agradável em Haskell, mas é um pouco complicado limitar o número de elementos. Portanto, para uma solução simples para o problema, primeiro considere a estúpida, mas funcional, dada por bradm.

Com a solução recursiva, o truque é passar uma variável "counter" para baixo na recursão e desabilitar a adição de mais elementos quando você atingir o máximo permitido. Isso pode ser feito bem com um 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)

Então

*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
leftaroundabout
fonte
Muito obrigado. Por ser um exercício para iniciantes, acho que é a abordagem mais fácil. Mas vou pensar na sua abordagem também.
mayerph 29/04
7

Por uma questão de integridade, deixe-me acrescentar uma abordagem alternativa "feia", que é, no entanto, bastante básica.

Lembre-se de que Maybe aé um tipo cujos valores são da forma Nothingou Just xpara alguns x :: a.

Portanto, reinterpretando os valores acima, podemos considerar Maybe aum "tipo de lista restrito", onde as listas podem ter zero ou um elemento.

Agora, (a, Maybe a)basta adicionar mais um elemento, portanto, é um "tipo de lista" onde as listas podem ter um ( (x1, Nothing)) ou dois ( (x1, Just x2)) elementos.

Portanto, Maybe (a, Maybe a)é um "tipo de lista" em que as listas podem ter zero ( Nothing), um ( Just (x1, Nothing)) ou dois ( (Just (x1, Just x2)) elementos.

Agora você deve entender como proceder. Quero enfatizar novamente que essa não é uma solução conveniente de usar, mas é um bom exercício para entendê-la (IMO).


Usando alguns recursos avançados do Haskell, podemos generalizar o acima usando uma família de tipos:

type family List (n :: Nat) (a :: Type) :: Type where
    List 0 a = ()
    List n a = Maybe (a, List (n-1) a)
chi
fonte
Esta resposta pode ser estendida com a família de tipos da lista baseada em Talvez do comprimento máximo n .
leftaroundabout 30/04
@leftaroundabout Feito. Isso pode ser um pouco demais para um iniciante, mas eu adicionei mesmo assim.
chi
no máximo três asegundos em Either () (a, Either () (a, Either () (a, Either () ())))... álgebra de tipo interessante foldr (.) id (replicate 3 $ ([0] ++) . liftA2 (+) [1]) $ [0] == [0,1,2,3],.
Will Ness