繁体   English   中英

GHC不能用GADT和存在类型推导出(a1~a)

[英]GHC cannot deduce (a1 ~ a) with GADTs and existential types

我的代码无法编译:

{-# LANGUAGE EmptyDataDecls, GADTs, RankNTypes  #-}

import Data.Ratio

data Ellipsoid
data Halfplane

data PointSet a where
    Halfplane :: RealFrac a => a -> a -> a -> (a -> a -> Bool) -> a -> PointSet Halfplane
    Ellipsoid :: RealFrac a => a -> a -> a -> (a -> a -> Bool) -> a -> PointSet Ellipsoid

type TestFunc =  RealFrac a => (a -> a -> a ->  Bool)

ellipsoid :: PointSet Ellipsoid -> TestFunc
ellipsoid (Ellipsoid a b c f r) = f' where f' z y x = ((x/a)^2 + (y/b)^2 + (z/c)^2) `f` r

halfplane :: PointSet Halfplane -> TestFunc
halfplane (Halfplane a b c f t) = f' where f' z y x = (a*x + b*y + c*z) `f` t

我得到的错误是:

Could not deduce (a1 ~ a)
[...]
Expected type: a -> a -> a -> Bool
  Actual type: a1 -> a1 -> a1 -> Bool
In the expression: f'
[...]

对于ellipsoidhalfplane两种功能。

我不明白,我正在寻找一个答案,为什么a不能等同于a1 ,两者都是RealFrac ,甚至更好:为什么推导出两种不同的类型( a ~ a1 )?

你使用GADT和隐含的forall会让你感到悲伤。 现在是提及“类型化存在量化” 反模式的好时机

既然你已经包括了约束RealFrac a中的定义PointSet你使用隐式forall是这样的:

data PointSet a where
    Halfplane :: forall a. RealFrac a => a -> a -> a -> (a -> a -> Bool) -> a -> PointSet HalfPlane
    Ellipsoid :: forall a. RealFrac a => ...

这同样适用于TestFunc

type TestFunc = forall a. RealFrac a => a -> a -> a -> Bool

这就是GHC强迫您添加RankNTypes扩展的原因。

由于foralla在构造函数PointSet不可能用统一aTestFunc因为aPointSet是一些具体的实例RealFrac ,但TestFunc是需要为任何一个工作功能a

特定类型a和普遍量化的forall a. a之间的这种差异forall a. a forall a. a导致GHC推导出两种不同的类型aa1

解决方案? 废弃所有这些存在的废话。 在需要的地方时间应用类型类约束:

{-# LANGUAGE DataKinds, GADTs, KindSignatures #-}

data Shape = Halfplane | Ellipsoid -- promoted via DataKinds

data PointSet (s :: Shape) a where
    Halfplane :: a -> a -> a -> (a -> a -> Bool) -> a -> PointSet Halfplane a
    Ellipsoid :: ...

type TestFunc a = a -> a -> a -> Bool

ellipsoid :: RealFrac a => PointSet Ellipsoid a -> TestFunc a
ellipsoid (Ellipsoid a b c f r) = f' where f' = ...

现在PointSet有两个参数:一个幻影类型s :: Shape ,它有种类Shape (种类是类型的类型)和a与你的原始例子相同,除了作为PointSet的显式参数,它不再是隐式存在量化的。

为了解决您的最后一点,在aa1错误消息都没有“均为RealFracRealFrac不是一个类型,它是一个类型类。 aa1是两个潜在的不同类型,无论碰巧的实例RealFrac

也就是说 ,除非你使用更具表现力的PointSet类型, PointSet有一个更简单的解决方案。

data PointSet a
    = Halfplane a a a (a -> a -> Bool) a
    | Ellipsoid a a a (a -> a -> Bool) a

testFunc :: RealFrac a => PointSet a -> TestFunc a
testFunc (Ellipsoid a b c f r) = f' where f' = ...
testFunc (Halfplane a b c f t) = f' where f' = ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM