簡體   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