loại để đại diện cho một danh sách có 0 đến 5 giá trị


14

Tôi có một bài tập trong đó tôi phải xác định một loại để biểu diễn một danh sách có từ 0 đến 5 giá trị. Đầu tiên tôi nghĩ rằng tôi có thể giải quyết đệ quy như thế này:

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

Nhưng tôi không nghĩ rằng đây là cách tiếp cận chính xác. Bạn có thể vui lòng cho tôi một thức ăn của suy nghĩ.

Câu trả lời:


12

Tôi sẽ không trả lời bài tập của bạn cho bạn - đối với bài tập, tốt hơn là bạn nên tự mình tìm ra câu trả lời - nhưng đây là một gợi ý sẽ đưa bạn đến câu trả lời: bạn có thể xác định danh sách có 0 đến 2 yếu tố như

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

Bây giờ, hãy nghĩ về cách bạn có thể mở rộng điều này đến năm yếu tố.


10

Chà, một giải pháp đệ quy chắc chắn là điều bình thường và thực tế là điều tốt đẹp ở Haskell, nhưng thật khó để hạn chế số lượng các yếu tố sau đó. Vì vậy, đối với một giải pháp đơn giản cho vấn đề, trước tiên hãy xem xét một giải pháp ngu ngốc nhưng hoạt động được đưa ra bởi bradm.

Với giải pháp đệ quy, mẹo là chuyển một biến đối lập trực tiếp xuống bộ đệ quy và sau đó vô hiệu hóa thêm các phần tử khi bạn đạt đến mức tối đa cho phép. Điều này có thể được thực hiện độc đáo với 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)

Sau đó

*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

cảm ơn rất nhiều. Bởi vì đó là một bài tập cho người mới bắt đầu, tôi nghĩ đó là cách tiếp cận dễ dàng hơn. Nhưng tôi sẽ nghĩ về cách tiếp cận của bạn quá.
mayerph

7

Để hoàn thiện, hãy để tôi thêm một cách tiếp cận thay thế "xấu xí", tuy nhiên khá cơ bản.

Nhớ lại rằng đó Maybe alà một loại có giá trị của mẫu Nothinghoặc Just xcho một số x :: a.

Do đó, bằng cách diễn giải lại các giá trị ở trên, chúng ta có thể coi Maybe alà "loại danh sách bị hạn chế" trong đó danh sách có thể có 0 hoặc một phần tử.

Bây giờ, (a, Maybe a)chỉ cần thêm một phần tử nữa, vì vậy nó là "loại danh sách" trong đó danh sách có thể có một ( (x1, Nothing)) hoặc hai ( (x1, Just x2)) phần tử.

Do đó, Maybe (a, Maybe a)là "loại danh sách" trong đó danh sách có thể có các phần tử zero ( Nothing), one ( Just (x1, Nothing)) hoặc hai ( (Just (x1, Just x2)).

Bây giờ bạn có thể hiểu làm thế nào để tiến hành. Hãy để tôi nhấn mạnh một lần nữa rằng đây không phải là một giải pháp thuận tiện để sử dụng, nhưng nó (IMO) là một bài tập tốt để hiểu về nó.


Sử dụng một số tính năng nâng cao của Haskell, chúng tôi có thể khái quát hóa những điều trên bằng cách sử dụng một loại họ:

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

Câu trả lời này có thể được mở rộng với họ danh sách có thể dựa trên chiều dài tối đa n .
leftaroundabout

@leftaroundabout Xong. Đó có thể là một chút quá nhiều cho người mới bắt đầu, nhưng tôi đã thêm nó vào.
chi

nhiều nhất là ba as trong Either () (a, Either () (a, Either () (a, Either () ())))... đại số loại thú vị foldr (.) id (replicate 3 $ ([0] ++) . liftA2 (+) [1]) $ [0] == [0,1,2,3],.
Will Ness
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.