将 Deriving Via 与 Phantom 类型结合使用
Using Deriving Via with Phantom Types
对冗长的重现表示歉意,但我没能缩短它。以下代码编译正常,直到最后一行:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
{-# LANGUAGE DerivingVia, DerivingStrategies, StandaloneDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Repro where
import Prelude hiding ((+))
class (Additive a) where
(+) :: a -> a -> a
data Vector2D u = Vector2D {
x :: u,
y :: u
}
addVector2 :: (Additive a) => Vector2D a -> Vector2D a -> Vector2D a
addVector2 Vector2D { x = x1, y = y1 } (Vector2D { x = x2, y = y2 }) =
Vector2D { x = x1 + x2, y = y1 + y2 }
instance (Additive a) => Additive (Vector2D a) where
(+) = addVector2
newtype Phantom1 d a = Phantom1 (Vector2D a) --Axial
deriving via (Vector2D a) instance forall d . (Additive a) => (Additive (Phantom1 d a))
data Via a b = Via a
class IsoEvidence a b where
convertTo :: a -> b
convertFrom :: b -> a
instance forall a b . (IsoEvidence a b, Additive b) => (Additive (Via a b)) where
(Via x) + (Via y) = Via $ convertFrom $ (convertTo x :: b) + (convertTo y :: b)
newtype Phantom2 d a = Phantom2 (Vector2D a) --Offset
instance (IsoEvidence (Phantom1 d a) (Phantom2 d a)) where
convertTo (Phantom1 x) = Phantom2 x
convertFrom (Phantom2 x) = Phantom1 x
deriving via (Via (Phantom2 d a) (Phantom1 d a))
instance (Additive a, IsoEvidence (Phantom1 d a) (Phantom2 d a)) =>
(Additive (Phantom2 d a))
之后我得到以下错误:
- 无法匹配类型
Vector2D a
的表示
与 Via (Phantom2 d a) (Phantom1 d a)
这似乎是在说它不能将 "Via &c" 强制转换为 "Vector2D a",这很奇怪,因为它实际上是一个两层深的新类型,而且工作正常。
我做错了什么?
DerivingVia
通过 newtypes 工作,但是你写了
data Via a b = Via a -- should be newtype
对冗长的重现表示歉意,但我没能缩短它。以下代码编译正常,直到最后一行:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, UndecidableInstances #-}
{-# LANGUAGE DerivingVia, DerivingStrategies, StandaloneDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Repro where
import Prelude hiding ((+))
class (Additive a) where
(+) :: a -> a -> a
data Vector2D u = Vector2D {
x :: u,
y :: u
}
addVector2 :: (Additive a) => Vector2D a -> Vector2D a -> Vector2D a
addVector2 Vector2D { x = x1, y = y1 } (Vector2D { x = x2, y = y2 }) =
Vector2D { x = x1 + x2, y = y1 + y2 }
instance (Additive a) => Additive (Vector2D a) where
(+) = addVector2
newtype Phantom1 d a = Phantom1 (Vector2D a) --Axial
deriving via (Vector2D a) instance forall d . (Additive a) => (Additive (Phantom1 d a))
data Via a b = Via a
class IsoEvidence a b where
convertTo :: a -> b
convertFrom :: b -> a
instance forall a b . (IsoEvidence a b, Additive b) => (Additive (Via a b)) where
(Via x) + (Via y) = Via $ convertFrom $ (convertTo x :: b) + (convertTo y :: b)
newtype Phantom2 d a = Phantom2 (Vector2D a) --Offset
instance (IsoEvidence (Phantom1 d a) (Phantom2 d a)) where
convertTo (Phantom1 x) = Phantom2 x
convertFrom (Phantom2 x) = Phantom1 x
deriving via (Via (Phantom2 d a) (Phantom1 d a))
instance (Additive a, IsoEvidence (Phantom1 d a) (Phantom2 d a)) =>
(Additive (Phantom2 d a))
之后我得到以下错误:
- 无法匹配类型
Vector2D a
的表示 与Via (Phantom2 d a) (Phantom1 d a)
这似乎是在说它不能将 "Via &c" 强制转换为 "Vector2D a",这很奇怪,因为它实际上是一个两层深的新类型,而且工作正常。
我做错了什么?
DerivingVia
通过 newtypes 工作,但是你写了
data Via a b = Via a -- should be newtype