- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的代码无法编译:
{-# 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'
[...]
对于ellipsoid
和halfplane
这两个函数。
我不明白并且正在寻找答案,为什么a
不能与a1
等同,两者都是RealFrac
,甚至更好:为什么推导出两种不同的类型(a ~ a1
)?
最佳答案
您对GADT
的使用隐式 forall
使你悲伤。现在是提一下“类型类的存在量化”的好时机 anti-pattern
由于您已包含约束 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
扩展名。
因为forall
a
在 PointSet
的构造函数中不可能与 a
统一在TestFunc
自 a
在PointSet
是RealFrac
的一些特定实例,但是TestFunc
是适用于任何 a
所需的函数。
具体类型之间的区别a
和普遍量化的forall a. a
导致 GHC 推断出两种不同的类型 a
和a1
.
解决方案?抛弃所有这些存在主义的废话。在需要的何处和何时应用类型类约束:
{-# 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
需要 2 个参数:幻像类型 s :: Shape
其中有种类Shape
(种类是类型的类型)和 a
这与您的原始示例相同,除了作为 PointSet
的显式参数它不再隐含地存在量化。
为了解决您的最后一点,a
和a1
错误消息中不是“都是 RealFrac
。RealFrac
不是类型,它是类型类。a
和 a1
是两种潜在不同类型,两者恰好是RealFrac
的实例。
也就是说,除非您使用更具表现力的类型 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' = ...
关于haskell - GHC 无法用 GADT 和存在类型推导出 (a1 ~ a),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24395644/
这三者之间有什么/为什么有区别? GADT(和常规数据类型)只是数据系列的简写吗?具体有什么区别: data GADT a where MkGADT :: Int -> GADT Int dat
我们能否将构造函数没有给定约束的 GADT 转换为具有上述约束的 GADT?我想这样做是因为我想要深度嵌入箭头,并使用(目前)似乎需要 Typeable 的表示来做一些有趣的事情。 (One reas
我试图将 mod-n 计数器表示为将间隔 [0, ..., n-1] 分成两部分: data Counter : ℕ → Set where cut : (i j : ℕ) → Counter (
这是一个示例代码: {-# LANGUAGE GADTs #-} data NumGadt a where NumGadt :: Num a => a -> Int -> String -> Bo
我为表达式创建了一个 GADT。当我对具有约束的构造函数进行模式匹配时,类型检查器无法推断构造函数约束中使用的类型变量的约束。我认为代码和错误消息更清楚。 {-# LANGUAGE GADTs, Mu
背景 我正在使用 Haskell 编写一个红黑树实现 依赖类型并且我在理解为什么下面的代码不起作用时遇到了一些麻烦。作为一种热身练习,我想做的是找到一个给定任意值的子树。不幸的是,我在编译代码并最终继
在他的论文 Generics for the Masses Hinze 回顾了数据类型的编码。 从 Nat 开始 data Nat :: ⋆ where Zero :: Nat Succ
当我尝试创建一个返回 Thing a 的函数时,我目前正与类型检查器发生冲突。 (其中 Thing 是 GADT)。一个最小的人为例子: {-#LANGUAGE GADTs, EmptyDataDec
考虑以下代码 data Foo f where Foo :: Foo Int class DynFoo t where dynFoo :: Foo f -> Foo t instance Dy
假设我正在编写一个 DSL,并希望同时支持幻像类型和错误类型的表达式。我的值(value)类型可能是 {-# LANGUAGE GADTs, DataKinds #-} data Ty = Num |
当answering a question with a suggestion to use GADTs ,评论中出现了一些关于性能的问题。问题涉及类型类 PlotValue : class Plot
我只是在阅读Dependent Types at Work .在参数化类型的介绍中,作者提到在这个声明中 data List (A : Set) : Set where [] : List A
考虑以下代码: data (:+:) f g a = Inl (f a) | Inr (g a) data A data B data Foo l where Foo :: Foo A data
是分机GADT在 Haskell 中破坏多态性,即使在不使用 GADT 的代码中? 这是一个有效但不使用 GADT 的示例 {-# LANGUAGE RankNTypes #-} --{-# LANG
这两个 GADT 声明之间有区别吗? data A a b where ... data A :: * -> * -> * where ... 最佳答案 没有区别。有人可能会认为,在构
我在 haskell 中建立了一个几何库。我不打算发布它,它只是我用来提高我的语言知识的一个项目。 我有一个 Local数据类型,定义如下 data Local a where MkLocal
我正在阅读 GADTs for dummies Haskell Wiki 上的页面,我仍然不明白如何以及为什么应该使用它们。作者举了一个励志的例子: data T a where D1 ::
我正在解析表单的一些语句 v1 = expression1 v2 = expression2 ... 我正在使用 State Monad 并且我的状态应该是一对 (String, Expr a),我真
如何使用广义代数数据类型? haskell wikibook 中给出的示例太短了,无法让我深入了解 GADT 的真正可能性。 最佳答案 我发现“Prompt”monad(来自“MonadPrompt”
我正在使用 learnyouahaskell 来介绍 GADT,并且我对它们可能的用途很感兴趣。据我了解,它们的主要特点是允许显式类型设置。 如: data Users a where GetUs
我是一名优秀的程序员,十分优秀!