我目前正在尝试实现一个类型类,它允许我将任何自定义类型转换为Integral
(这些类型都应该可以转换为索引或权重)。在这种特殊情况下,我想用它来确保给定八度音阶上的音符可以转换为钢琴键盘键的索引:
import Data.Int
class Convertible a where
toIntegral :: Integral b => a -> b
data Note = Note Tone Int
instance Convertible Note where
toIntegral (Note t o) = o * 12 + toIntegral t
然而,编译器抱怨我toIntegral
的{{1}}实现不符合我的Note
类型类。
Convertible
据我了解,当我将 • Couldn't match expected type ‘b’ with actual type ‘Int’
‘b’ is a rigid type variable bound by
the type signature for:
num :: forall b. Integral b => Note -> b
at src/Note.hs:11:5
• In the expression: octave * 12 + (num tone)
In an equation for ‘num’:
num (Note tone octave) = octave * 12 + (num tone)
In the instance declaration for ‘Convertible Note’
• Relevant bindings include
num :: Note -> b (bound at src/Note.hs:11:5)
函数约束为toIntegral
时,它会将a -> Int
函数的内容评估为Integral => b -> a -> b
。现在我不明白什么是错的,因为Int
实现了Integral
类型类,对吧?
你能帮我理解我在这里做错了吗?
答案 0 :(得分:2)
类型变量由调用者选择,而不是由被调用者选择。在您的情况下,toIntegral
无法选择b
,其来电者会这样做。根据其类型,所有这些用途必须键入检查
toIntegral (Note t o) :: Int
toIntegral (Note t o) :: Integer
toIntegral (Note t o) :: Word32
-- etc.
解决方案也是转换Int
,即转换o
,以便返回任何整数b
,而不仅仅是Int
。
例如,fromIntegral o
可以将o
转换为任何Num
类型,因此任何Integral
类型。
无论如何,你确定你的toIntegral
确实需要这种类型吗?