тип представлення списку з 0 до 5 значень


14

У мене є вправа, де я повинен визначити тип для представлення списку зі значеннями від 0 до 5. Спочатку я подумав, що можу вирішити це рекурсивно так:

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

Але я не думаю, що це правильний підхід. Чи можете ви, будь ласка, дати мені страву думки.

Відповіді:


12

Я не відповім на вашу вправу для вас - для вправ краще зрозуміти відповідь самостійно - але ось підказка, яка повинна привести вас до відповіді: ви можете визначити список з 0 до 2 елементів як

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

А тепер подумайте, як можна розширити це до п’яти елементів.


10

Ну, рекурсивне рішення - це звичайно нормальна і насправді приємна річ у Haskell, але трохи складніше обмежувати кількість елементів тоді. Отже, для простого вирішення проблеми спочатку розгляньте дурний, але працездатний, наданий bradm.

У випадку рекурсивного рішення фокус полягає в тому, щоб пропустити змінну «лічильник» вниз по рекурсії, а потім відключити витрату більше елементів, коли ви досягнете максимально дозволеного. Це можна добре зробити за допомогою 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)

Тоді

*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

дуже дякую. Тому що це вправа для початківців, я думаю, що це легший підхід. Але я подумаю і про ваш підхід.
Майерф

7

Для повноти дозвольте додати «потворний» альтернативний підхід, який, проте, є досить базовим.

Нагадаємо, Maybe aце тип, значення якого мають форму Nothingабо Just xдля деяких x :: a.

Отже, переосмислюючи наведені вище значення, ми можемо розглядати Maybe aяк "тип списку з обмеженим доступом", де списки можуть мати нуль або один елемент.

Тепер (a, Maybe a)просто додаємо ще один елемент, тож це "тип списку", де списки можуть мати один ( (x1, Nothing)) або два ( (x1, Just x2)) елементи.

Отже, Maybe (a, Maybe a)це "тип списку", де списки можуть мати нуль ( Nothing), один ( Just (x1, Nothing)) або два ( (Just (x1, Just x2)) елементи.

Тепер ви повинні мати можливість зрозуміти, як діяти. Дозвольте ще раз наголосити, що це не зручне рішення для використання, але це (ІМО) приємна вправа зрозуміти це все одно.


Використовуючи деякі розширені функції Haskell, ми можемо узагальнити вищезазначене, використовуючи сімейство типів:

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

Цю відповідь можна було б розширити сімейством типів списку на основі можливостей n max-length n .
близько

@leftaroundabout Готово. Це може бути трохи занадто для початківця, але я все одно додав його.
чі

максимум три aз в Either () (a, Either () (a, Either () (a, Either () ())))... цікавому типі алгебри foldr (.) id (replicate 3 $ ([0] ++) . liftA2 (+) [1]) $ [0] == [0,1,2,3].
Буде Несс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.