[英]Haskell Typeclass Type Constraints and Deduction
我一直在閱讀“Learn You a Haskell”一書,我正試圖將我的腦袋包裹在Haskell Type Classes中。 作為練習,我正在嘗試創建一個簡單的矢量類型類。 以下代碼片段給了我一些悲傷(導致我第一篇發布到StackOverflow):
data Vec2 a = Vec2 (a,a) deriving (Show, Eq, Read)
class Vector a where
(<*) :: (Num b) => a -> b -> a
instance (Num a) => Vector (Vec2 a) where
Vec2 (x,y) <* a = Vec2 (a*x, a*y)
我收到以下錯誤消息:
Could not deduce (a~b) from the context (Num a) or from (Num b) bound by the type signature for
<* :: Num b => Vec2 a -> b -> Vec2 a
這似乎是Num
在類型類應該提供的類型指定a
,和Num a
實例中應該提供的類型spefication x
和y
,那么為什么抱怨? 我對這段代碼有什么誤解?
(*) :: Num a => a -> a -> a
。 但是,當您實際嘗試使用*
,實際上您將兩個具有Num
實例的不相關類型相乘,並且編譯器無法推斷它們是相同的。
為了更清楚地解釋它,請看<*
的類型和b
的通用量化
(<*) :: (Num b) => a -> b -> a
你在這里說的是,給我任何類型的Num
實例,我將能夠將它與我的向量相乘,但你想說的是不同的東西。
你需要知道a
類型Vec2 a
中的b
與類型(<*) :: Num b => a -> b -> a
,然后才能將它們相乘。 這是一個使用typefamilies來確保這種約束的解決方案。
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
data Vec2 a = Vec2 (a,a) deriving (Show, Eq, Read)
class (Num (VectorOf a)) => Vector a where
type VectorOf a :: *
(<*) :: a -> (VectorOf a) -> a
instance (Num a) => Vector (Vec2 a) where
type VectorOf (Vec2 a) = a
Vec2 (x,y) <* a = Vec2 (a*x, a*y)
編譯器無法驗證所涉及的兩個Num
實例實際上是否為同一類型。 當然,它們都是Num
實例,但是還需要它們必須是同一個實例。
否則,你可以寫這樣的東西:
Vec2 (1 :: Double, 2 :: Double) <* (3 :: Int)
什么時候不能飛,ex: (1 :: Double) * (3 :: Int)
。
我認為問題是(*)
的類型(Num a) => a -> a -> a
而不是(Num a, Num b) => a -> b -> a
complier expect。
我不熟悉Haskell的數字轉換,但我的解決方法有限,因為第二個參數是Integral
一個實例。
data Vec2 a = Vec2 (a,a) deriving (Show, Eq, Read)
class Vector a where
(<*) :: (Integral b) => a -> b -> a
instance (Num a) => Vector (Vec2 a) where
Vec2 (x,y) <* a = Vec2 (x*b, y*b)
where b = fromIntegral a
因為fromIntegral
有類型(Integral a, Num b) => a -> b
,它可以根據需要轉換*
的第二個參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.