0 ila 5 değer içeren bir listeyi temsil etmek için tür


14

Ben 0 ile 5 değerleri olan bir liste temsil etmek için bir tür tanımlamak zorunda bir egzersiz var. İlk olarak bunu tekrar tekrar böyle çözebileceğimi düşündüm:

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

Ama bunun doğru bir yaklaşım olduğunu düşünmüyorum. Bana bir düşünce yemeği verir misin?

Yanıtlar:


12

Egzersizinizi sizin için cevaplamayacağım - egzersizler için, cevabı kendiniz bulmak daha iyidir - ancak burada sizi cevaba götürecek bir ipucu: 0 ila 2 elemanlı bir liste tanımlayabilirsiniz

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

Şimdi, bunu nasıl beş unsura genişletebileceğinizi düşünün.


10

Haskell'de özyinelemeli bir çözüm kesinlikle normal ve aslında güzel bir şeydir, ancak o zaman öğe sayısını sınırlamak biraz zor. Bu nedenle, soruna basit bir çözüm için, önce bradm tarafından verilen aptalca ama çalışanı düşünün.

Özyinelemeli çözümde, püf noktası özyinelemeden bir “sayaç” değişkeni iletmek ve sonra izin verilen maksimum değere ulaştığınızda daha fazla öğe almayı devre dışı bırakmaktır. Bu bir GADT ile güzelce yapılabilir:

{-# 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)

Sonra

*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

çok teşekkürler. Yeni başlayan bir egzersiz olduğu için bence daha kolay bir yaklaşım. Ama ben de senin yaklaşımını düşüneceğim.
mayerph

7

Tamlık uğruna, "çirkin" bir alternatif yaklaşım eklememe izin verin, ancak bu oldukça basittir.

Maybe aDeğerleri formda olan Nothingveya Just xbazıları için olan bir tür olduğunu hatırlayın x :: a.

Bu nedenle, yukarıdaki değerleri yeniden yorumlayarak, Maybe alistelerin sıfır veya bir öğeye sahip olabileceği bir "kısıtlı liste türü" olarak değerlendirebiliriz.

Şimdi, (a, Maybe a)bir öğe daha eklediğinden listelerin bir ( (x1, Nothing)) veya iki ( (x1, Just x2)) öğeye sahip olabileceği bir "liste türü" dir .

Bu nedenle, Maybe (a, Maybe a)listelerin sıfır ( Nothing), bir ( Just (x1, Nothing)) veya iki ( (Just (x1, Just x2)) öğeye sahip olabileceği bir "liste türü" dür.

Şimdi nasıl ilerleyeceğinizi anlayabilmelisiniz. Bunun kullanımı için uygun bir çözüm olmadığını tekrar vurgulayayım, ama yine de anlamak için güzel bir egzersiz (IMO).


Haskell'in bazı gelişmiş özelliklerini kullanarak, yukarıdakileri bir tür aile kullanarak genelleştirebiliriz:

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

Bu cevap, belki de en fazla uzunluk n olan liste tabanlı liste ailesi ile genişletilebilir .
leftaroundabout

@leftaroundabout Tamamlandı. Bu yeni başlayanlar için biraz fazla olabilir, ama yine de ekledim.
chi

en çok üç as Either () (a, Either () (a, Either () (a, Either () ())))... ilginç tip cebir foldr (.) id (replicate 3 $ ([0] ++) . liftA2 (+) [1]) $ [0] == [0,1,2,3],.
Ness Ness
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.