我正在摆弄Haskell,但却遇到了问题。以下代码:
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的东西,在它上面调用这个方法应该告诉我马(好吧,马,开头 - 这将包括很快的列表),它有。
我犯了一个简单的错误或误解了一些更基本的东西吗?
答案 0 :(得分: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
答案 1 :(得分:0)
正如上面评论中所述,(InHorses r) => e -> r
的{{1}}类型意味着,如果给定类型为yieldInHorses
的值,则可以返回值 any < / strong>类型e
满足r
约束。但是,该实现始终会返回特定的InHorses
,r
。
由于示例似乎不完整(在Horse
的实现中忽略Stable
值),因此很难知道什么最适合您。如果yieldInHorses
只能 生成Stable
,那么函数依赖或类型族方法是有意义的。但是,如果Horse
维护了一些可以用于生成任何Stable
的状态,那么构造函数方法可能会很有用。例如,如果所有InHorses r => r
都可以从InHorses
:
String