เหตุใดฉันจึงไม่สามารถทำให้ String เป็นอินสแตนซ์ของประเภทคลาสได้


85

ให้ :

data Foo =
  FooString String
class Fooable a where --(is this a good way to name this?)
  toFoo :: a -> Foo

ฉันต้องการสร้างStringตัวอย่างของFooable:

instance Fooable String where
  toFoo = FooString

GHC ก็บ่นว่า:

Illegal instance declaration for `Fooable String'
    (All instance types must be of the form (T t1 ... tn)
     where T is not a synonym.
     Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Fooable String'

ถ้าฉันใช้[Char]:

instance Fooable [Char] where
  toFoo = FooString

GHC บ่น:

Illegal instance declaration for `Fooable [Char]'
   (All instance types must be of the form (T a1 ... an)
    where a1 ... an are type *variables*,
    and each type variable appears at most once in the instance head.
    Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Fooable [Char]'

คำถาม :

  • เหตุใดฉันจึงไม่สามารถสร้าง String และอินสแตนซ์ของประเภทคลาสได้
  • GHC ดูเหมือนเต็มใจที่จะให้ฉันหลีกหนีจากสิ่งนี้หากฉันเพิ่มธงพิเศษ นี่เป็นความคิดที่ดีหรือไม่?

6
นี่เป็นคำถามประเภทที่ฉันโหวตและทำเครื่องหมายว่าเป็นที่ชื่นชอบเพราะไม่เช่นนั้นฉันรู้ว่าในอนาคตอันใกล้นี้ฉันจะถามมัน;)
Oscar Mederos

3
เกี่ยวกับการตั้งค่าสถานะพิเศษอาจเป็นความคิดที่ดีตราบใดที่คุณไว้วางใจ GHC และเข้าใจว่าธงทำอะไร Yesodอยู่ในใจ: มันสนับสนุนให้คุณใช้ OverloadedStrings pragma เสมอเมื่อเขียนแอพ Yesod และ QuasiQuotes เป็นสิ่งจำเป็นสำหรับกฎการกำหนดเส้นทาง Yesod โปรดทราบว่าแทนที่จะตั้งค่าสถานะในเวลาคอมไพล์คุณยังสามารถใส่{-# LANGUAGE FlexibleInstances #-}(หรือ pragma อื่น ๆ ) ที่ด้านบนของไฟล์. hs ของคุณ
Dan Burton

คำตอบ:


65

นี้เป็นเพราะStringเป็นเพียงนามแฝงประเภทสำหรับ[Char]ซึ่งเป็นเพียงการประยุกต์ใช้ตัวสร้างประเภท[]กับชนิดดังนั้นนี้จะอยู่ในรูปแบบChar ([] Char)ซึ่งไม่ใช่รูปแบบ(T a1 .. an)เนื่องจากCharไม่ใช่ตัวแปรประเภท

เหตุผลของข้อ จำกัด นี้คือเพื่อป้องกันไม่ให้อินสแตนซ์ทับซ้อนกัน ตัวอย่างเช่นสมมติว่าคุณมีinstance Fooable [Char]และหลังจากนั้นก็มีคนมาหาและกำหนดไฟล์instance Fooable [a]ไฟล์. ตอนนี้คอมไพเลอร์จะไม่สามารถระบุได้ว่าคุณต้องการใช้ตัวใดและจะแสดงข้อผิดพลาด

โดยใช้ -XFlexibleInstancesทั่วไปแล้วคุณสัญญากับคอมไพเลอร์ว่าจะไม่กำหนดอินสแตนซ์ดังกล่าว

ขึ้นอยู่กับสิ่งที่คุณพยายามจะทำมันอาจจะดีกว่าที่จะกำหนดกระดาษห่อหุ้ม:

newtype Wrapper = Wrapper String
instance Fooable Wrapper where
    ...

4
มาพูดเพื่อโต้แย้งว่าฉันก็ต้องการinstance Fooable [a]เช่นกัน มีวิธีทำให้toFooฟังก์ชั่นทำงานแตกต่างกันaหรือไม่ถ้าเป็น Char?
John F.Miller

7
@ จอห์น: มีส่วนขยาย-XOverlappingInstancesที่จะอนุญาตสิ่งนี้และเลือกอินสแตนซ์ที่เฉพาะเจาะจงที่สุด โปรดดูที่คู่มือผู้ใช้ GHC สำหรับรายละเอียด
hammar

18

คุณกำลังพบกับข้อ จำกัด สองประการของแว่นตาคลาสสิก Haskell98:

  • พวกเขาไม่อนุญาตคำพ้องความหมายประเภทในอินสแตนซ์
  • พวกเขาไม่อนุญาตประเภทที่ซ้อนกันซึ่งไม่มีตัวแปรประเภท

ข้อ จำกัด ที่ยุ่งยากเหล่านี้ถูกยกเลิกโดยส่วนขยายสองภาษา:

  • -XTypeSynonymInstances

ซึ่งอนุญาตให้คุณใช้คำพ้องความหมายประเภท (เช่นStringสำหรับ[Char]) และ:

  • -XFlexibleInstances

ซึ่งยกข้อ จำกัด เกี่ยวกับประเภทอินสแตนซ์ให้อยู่ในรูปแบบT a b ..ที่พารามิเตอร์เป็นตัวแปรประเภท -XFlexibleInstancesธงช่วยให้หัวของการประกาศอินสแตนซ์ที่จะกล่าวถึงประเภทที่ซ้อนกันโดยพลการ

โปรดทราบว่าการยกข้อ จำกัด เหล่านี้บางครั้งอาจทำให้เกิดอินสแตนซ์ที่ทับซ้อนกันซึ่ง ณ จุดนั้นอาจจำเป็นต้องใช้ส่วนขยายภาษาเพิ่มเติมเพื่อแก้ไขความไม่ชัดเจนซึ่งทำให้ GHC สามารถเลือกอินสแตนซ์ให้คุณได้


อ้างอิง ::


4

FlexibleInstances ไม่ใช่คำตอบที่ดีในกรณีส่วนใหญ่ ทางเลือกที่ดีกว่าคือการรวม String ในประเภทใหม่หรือแนะนำคลาสตัวช่วยดังนี้:

class Element a where
   listToFoo :: [a] -> Foo

instance Element Char where
   listToFoo = FooString

instance Element a => Fooable [a] where
   toFoo = listToFoo

ดูเพิ่มเติม: http://www.haskell.org/haskellwiki/List_instance


2

การเพิ่มคำตอบเหล่านี้หากคุณไม่สะดวกในการยกข้อ จำกัด อาจมีบางกรณีที่ควรรวม String ของคุณในรูปแบบใหม่ซึ่งอาจเป็นตัวอย่างของคลาส การแลกเปลี่ยนอาจเป็นความอัปลักษณ์ที่อาจเกิดขึ้นได้โดยต้องห่อและแกะรหัสของคุณ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.