[英]Why can't GHC typecheck this function involving polymorphism and existential types?
[英]Why does GHC refuse to allow this existential type function?
我已經定義了一個通用的heterogenous ,我稱之為(我不知道這是否正確),輸入:
data Heterotype f = forall a. f a => Heterotype a
然后我決定創建一個函數,允許您從多態值創建異型:
hset :: (forall a. f a => a) -> Heterotype f
hset x = Heterotype x
但是,GHC 抱怨以下內容:
████████.hs:15:10: error:
* Could not deduce: f a0 arising from a use of `Heterotype'
* In the expression: Heterotype x
In an equation for `hset': hset x = Heterotype x
* Relevant bindings include
x :: forall a. f a => a
(bound at ████████.hs:15:6)
hset :: (forall a. f a => a) -> Heterotype f
(bound at ████████.hs:15:1)
|
15 | hset x = Heterotype x
| ^^^^^^^^^^^^
編輯:啟用以下擴展:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE GADTs, ScopedTypeVariables #-}
{-# LANGUAGE NoStarIsType, ConstraintKinds #-}
{-# LANGUAGE AllowAmbiguousTypes, RankNTypes #-}
import Data.Kind
從邏輯的角度來看,您的代碼將對應於邏輯公式的證明,可以如下(粗略地)閱讀:
f
是任何類型的屬性;f
任何類型a
,我們可以產生類型a
的值x
;f
且值為x
的類型a
。 這在邏輯上是不合理的。 事實上,無論a
是什么, fa
都可能永遠不成立。 在這種情況下,上面的假設空洞地成立,因此它是正確的。 然而,上述結論與fa
總是錯誤的事實相矛盾。
因此,我們無法使用該類型定義您的hset
。
為了使論證合理,我們必須添加一個額外的假設,即存在某種類型b
使屬性f
真。 如果我們加上這個假設,我們可以證明這個陳述:
-- (untested, but should work)
hset :: forall b . f b => (forall a. f a => a) -> Heterotype f
hset x = Heterotype (x :: b)
您的數據定義隱藏的monotyped選擇a
被包裝起來,從詞典的價值f
。 重要的是要認識到,這樣做的全部意義在於丟棄有關特定類型的信息,同時保留與該類型關聯的實例字典。
這與您在hset
嘗試執行的操作不hset
。 從來沒有一個具體的類型來打包實例。 這些部分不能以這種方式組合在一起,因為它們都缺少相同的必需的東西。 Heterotype f
和(forall a. fa => a)
都缺乏一個具體的類型來選擇一個實例,但是Heterotype
構造器需要一個具體的實例來包含。 只是信息不存在。 這些部分是不兼容的。
您有點過度指定了:),以下工作正常:
data Heterotype f = forall a. f a => Heterotype a
hset :: forall f a. f a => a -> Heterotype f
hset x = Heterotype x
不同之處在於您已經量化了您的參數: (forall a. fa => a)
表示此函數接受一個表達式,該表達式必須同時是任何可能的類型(調用者不能選擇特定的“a”) ,這真的沒有意義。 新版本(因此是相同的只是用Heterotype
自身的構造函數)說,來電者被允許挑選的類型a
,它可以是任何東西,但必須只有一個類型(一次有效)。
習慣存在主義可能需要一些練習; 最好的方法是反復試驗:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.