未能与实际类型'Horse'匹配预期类型'r'

问题描述:

我在与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

我认为您在寻找关联类型

{-# 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

如上文的评论中提到,类型(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"