簡體   English   中英

Typeclass方法可在Haskell中返回另一個類型類

[英]Typeclass method which returns another typeclass in Haskell

我必須在Haskell中定義2個類型類。 一種很簡單-它實現了Ord,並且具有一種將給定類型轉換為int的方法。 像這樣:

class (Ord a) => Id a where
  toInt :: a -> Int

which has a method . 但是然后我有了另一個具有方法的類型類 typeclass. 此方法應返回類型類。 所以我寫了這樣的東西:

class HasId a where
  getId :: a -> Id a 

我收到一個我不知道如何解決的錯誤。

• Expected kind ‘* -> Constraint’, but ‘Int’ has kind ‘*’
• In the class declaration for ‘HasId’
 |
 | class (Int a) => HasId a where     |        ^^^^^

• Expected a type, but ‘Id a’ has kind ‘Constraint’
• In the type signature: getId :: a -> Id a
  In the class declaration for ‘HasId’
 |
 |  getId :: a -> Id a     |             

有人可以告訴我如何在另一個人的typeclass方法中返回typeclass嗎? typeclass at first? 我應該首先實現類型類的某些實例嗎?

要明白,一個Haskell是很重要的class是在面向對象的語言類非常不同的。 這是一個類型類 ,即它“將類型的集合分組在一起”,而OO類將的集合分組在一起。 IOW,OO類一種類型(包含值),但是Haskell類實際上是某種類型的類型

現在,函數/方法始終將值作為參數,並返回值作為結果。 但是它不能給您返回類型,也不能給您“類型類的值”,因為沒有這種東西。

相反,使用類型類的方式是這樣的:編寫一個多態函數 ,即一個接受或產生未指定類型的值的函數。 這就是類型變量的用途。 通常,多態簽名意味着函數可以處理任何類型的值,例如

length :: [a] -> Int

它接受一個列表,並不關心其元素的類型。 但是然后您說您確實在乎使用了什么類型,即,您要求它們在類中。 這是一個約束 ,它是用=>表示法編寫的。 toInt實際上具有簽名(由類聲明自動生成)

toInt :: Id a => a -> Int

坦白說,我懷疑這真的是您想要的。 如果你可以用做Id a是將其轉換為Int ,那么結果一個有效的Int (只是一個類型的注釋這表明什么樣的對象的此ID屬於),而不管的a參數。 因此,您應該考慮使用Id類型來代替Id

newtype Id' a = Id {toInt :: Int}  -- The prime ' symbol has no particular meaning,
                                   -- I just use it for disambiguation.

然后,你有更明智的類型

toInt :: Id' a -> Int

不需要任何限制。

newtype與OO類非常相似,因為它實際上定義了一個具體類型,該類型具有可以傳遞的值。

getId方法也是一個受約束的多態函數,它可以接受“具有Id ”並返回給您該Id的內容。 在這種情況下,一個類是有意義的(因為您可以具有不同的數據結構,這些數據結構可能以不同的方式存儲其ID)。 現在實際上是

class HasId a where
  getId :: a -> Id' a

根據Welperooni的回答 ,使用原始Id類定義HasId確實也是可以HasId ,只是這實際上沒有多大意義。 Id可用作 Id 的所有類型 您可以表示getId可以產生任何這種類型的ID:

class HasId a where
  getId :: Id b => a -> b

請注意,result-Id類型現在完全獨立於您要計算其ID的對象的類型。 b可以始終是任何 Id類型。 就像我說的那樣,這沒有任何意義:為什么您需要大量代表Ids的不同類型,卻需要所有HasId類型來支持所有這些類型?

實際上,這無法按現狀實現,因為沒有機制可以讓您生成任意Id類型的Id 這將需要其他方法

class Id a where
  toInt :: a -> Int
  fromInt :: Int -> a

現在你可以做

class HasId a where
  getId :: Id b => a -> b

data SomeObj { objName :: String
             , objId :: Int }

instance HasId SomeObj where
  getId (SomeObj _ i) = fromInt i

但是,如果您要求任何Id類型都可以從Int轉換為Int ,則這些類型必須Int本身同構。 因此, newtype Id' a方法幾乎可以肯定更好。

您將返回值聲明為HKT Id a ,但您想要的是另一種類型,受類型類Id約束。

您需要的不是getId :: a -> Id a ,而是getId :: Id b => a -> b

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM