พิมพ์เพื่อเป็นตัวแทนรายการที่มีค่า 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

ขอบคุณมาก. เพราะมันเป็นแบบฝึกหัดเริ่มต้นฉันคิดว่ามันเป็นวิธีที่ง่ายกว่า แต่ฉันจะคิดถึงวิธีการของคุณด้วย
mayerph

7

เพื่อความสมบูรณ์ฉันขอเพิ่มวิธีการทางเลือก "น่าเกลียด" ซึ่งเป็นพื้นฐานที่ค่อนข้างง่าย

จำได้ว่าMaybe aเป็นชนิดที่มีค่าเป็นในรูปแบบNothingหรือสำหรับบางคนJust xx :: a

ดังนั้นโดยการตีความค่าข้างต้นใหม่เราสามารถพิจารณาMaybe aว่าเป็น "ประเภทลิสต์ที่ถูก จำกัด " ซึ่งลิสต์อาจมีองค์ประกอบที่เป็นศูนย์หรือหนึ่งองค์ประกอบ

ตอนนี้(a, Maybe a)เพียงเพิ่มองค์ประกอบอีกหนึ่งรายการดังนั้นจึงเป็น "ประเภทรายการ" ที่รายการสามารถมีองค์ประกอบหนึ่ง ( (x1, Nothing)) หรือสอง ( (x1, Just x2))

ดังนั้นจึงMaybe (a, Maybe a)เป็น "ประเภทรายการ" ที่รายการสามารถมีองค์ประกอบศูนย์ ( Nothing), หนึ่ง ( Just (x1, Nothing)) หรือสอง ( (Just (x1, Just x2)) องค์ประกอบ

ตอนนี้คุณควรจะสามารถเข้าใจวิธีการดำเนินการต่อไป ให้ฉันเครียดอีกครั้งว่านี่ไม่ใช่วิธีแก้ปัญหาที่สะดวกในการใช้ แต่เป็น (IMO) การออกกำลังกายที่ดีที่จะเข้าใจมันต่อไป


ด้วยการใช้คุณสมบัติขั้นสูงของ Haskell เราสามารถพูดคุยด้านบนโดยใช้ประเภทตระกูล:

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

คำตอบนี้อาจจะขยายกับครอบครัวประเภทของรายการอาจจะตามความยาวสูงสุดn
leftaroundabout

@leftaroundabout เรียบร้อยแล้ว นั่นอาจจะมากเกินไปสำหรับผู้เริ่มต้น แต่ฉันเพิ่มไว้แล้ว
Chi

อย่างน้อยที่สุดสามaในEither () (a, Either () (a, Either () (a, Either () ())))... พีชคณิตประเภทที่น่าสนใจ, foldr (.) id (replicate 3 $ ([0] ++) . liftA2 (+) [1]) $ [0] == [0,1,2,3].
Will Ness
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.