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?

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.


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’

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)

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.