2016-08-04 88 views
2

我在與Haskell一起擺弄,但正在努力解決問題。下面的代碼:未能與實際類型'Horse'匹配預期類型'r'

class HasHorses e where yieldInHorses :: (InHorses r) => e -> r 
class InHorses e 

data Horse = Horse String 
data Stable = Stable String 

instance InHorses Horse 
instance HasHorses Stable where yieldInHorses e = (Horse "Buttercup") 

使我有以下錯誤:

source_file.hs:10:52: error: 
    • Couldn't match expected type ‘r’ with actual type ‘Horse’ 
     ‘r’ is a rigid type variable bound by 
     the type signature for: 
      yieldInHorses :: forall r. InHorses r => Stable -> r 
     at source_file.hs:10:33 
    • In the expression: (Horse "Buttercup") 
     In an equation for ‘yieldInHorses’: 
      yieldInHorses e = (Horse "Buttercup") 
     In the instance declaration for ‘HasHorses Stable’ 
    • Relevant bindings include 
     yieldInHorses :: Stable -> r 
      (bound at source_file.hs:10:33) 

哪裏線10指的是行,我instance HasHorses Stable where ...

也許我忽略了一些東西,但我不明白爲什麼這應該是一個錯誤。實際的Type Horse滿足r的約束條件,即它應該是InHorses。

'yieldInHorses'方法的想法是,對於HasHorses來說,調用這個方法應該告訴我馬匹(好吧,馬,開始 - 這將包括很快列表),它有。

我做了一個簡單的錯誤還是誤解了一些更基礎的東西?

+2

類型yieldInHorses'的'實際上是'的forall河InHorses r => e - > r',這意味着*調用者可以決定*'r'應該是什麼。你正在尋找的東西就像'exists'而不是'forall',雖然[它可以使用其他結構對它們進行類似的編碼](https://wiki.haskell.org/ Existential_type)。然而,這是一個這樣一個人爲的例子,很難給出具體的建議 - 爲什麼你會需要像InHorses這樣的類型類型呢? –

+1

而不是'InHorses r => e - > r'只需使用'e - > Horses',其中'Horses'是一種可以正確捕捉所有想要的信息的類型,可能是[Horse]'。 – user2407038

+1

我想知道你爲什麼使用類型類。你真的需要他們嗎?如果一個類型類只有一個實例,那麼你可能應該放棄它並直接使用plain類型。 – chi

回答

3

我認爲您在尋找關聯類型

{-# LANGUAGE TypeFamilies #-} 
{-# LANGUAGE FlexibleContexts #-} 

class HasHorses e where 
    type R e :: * 
    yieldInHorses :: (InHorses (R e)) => e -> R e 

class InHorses e 

data Horse = Horse String 
data Stable = Stable String 

instance InHorses Horse 

instance HasHorses Stable where 
    type R Stable = Horse 
    yieldInHorses e = (Horse "Buttercup") 

test = yieldInHorses (Stable "asd") 

這裏當我們定義我們還定義 關聯的馬是什麼類型的HasHorses實例。

由於@Alexis King提到,您的yieldInHorses的簽名允許調用者確定返回類型是什麼。例如,他們 可以問:

yieldInHorses (Stable "asd") :: Int 

但似乎你想要返回根據您所定義的實例的特定類型。

更新

這裏是花葯的方式來編寫簽名yieldInHorses從而消除 需要FlexibleContexts並與GHC 8部作品:

yieldInHorses :: (InHorses r, r ~ R e) => e -> r 
+0

我想你或者需要添加'{ - #LANGUAGE Con​​strainedClassMethods# - }'或將'(InHorses(R e))=> HasHorses e'放入類定義中,以便將其編譯到GHC 8.0.1中 –

+0

Ok謝謝 - 我只用7.10.x測試過。 – ErikR

+0

用yieldInHorses的替代簽名更新了答案。 – ErikR

0

如上文的評論中提到,類型(InHorses r) => e -> ryieldInHorses意味着如果給定值e,它能夠返回的任意值類型r t帽子滿足InHorses約束。但是,實施始終返回特定的r,Horse

由於該示例看起來不完整(在執行yieldInHorsesStable的值被忽略),很難知道哪種方法最適合您。如果一個Stable可以只有產生Horse s,功能依賴或類型家庭方法是有道理的。然而,如果一個Stable保持某種狀態,然後可以用於生成任何InHorses r => r,也許構造方法可能是有用的。例如,如果所有InHorses能夠被從一個String構造:

class InHorses e where makeHorse :: String -> e 
instance InHorses Horse where makeHorse s = Horse s 

instance HasHorses Stable where yieldInHorses e = makeHorse "Buttercup" 
相關問題