在下面的示例中,我試圖使foo
返回其「預期」多態輸出類型。想法是foo
返回一個多態值和一個存在類型,然後bar
指定元組的類型爲隱藏類型。 (當然,這只是工作,如果在bar
種類也存在,這是真的在我的情況)以下示例編譯:帶約束條件的循環打字
{-# LANGUAGE GADTs, ScopedTypeVariables #-}
module Foo where
import Data.Proxy
import Data.Typeable
data HiddenType where
Hidden :: (Typeable a) => Proxy a -> HiddenType
foo :: (i,HiddenType)
foo = (undefined, Hidden (Proxy::Proxy Int))
data Foo where
Foo :: i -> Foo
bar :: Foo
bar =
let (x,h) = foo
in case h of
(Hidden (p::Proxy i)) -> Foo (x :: i)
我真的需要foo
一個Typeable
約束:
foo :: (Typeable i) => (i,HiddenType)
當我再補充一點約束(沒有其他變化),我得到這些錯誤:
Foo.hs:20:15:
No instance for (Typeable t0) arising from a use of ‘foo’
The type variable ‘t0’ is ambiguous
Relevant bindings include x :: t0 (bound at Foo.hs:20:8)
Note: there are several potential instances:
instance [overlap ok] Typeable()
-- Defined in ‘Data.Typeable.Internal’
instance [overlap ok] Typeable Bool
-- Defined in ‘Data.Typeable.Internal’
instance [overlap ok] Typeable Char
-- Defined in ‘Data.Typeable.Internal’
...plus 14 others
In the expression: foo
In a pattern binding: (x, h) = foo
In the expression:
let (x, h) = foo
in case h of { (Hidden (p :: Proxy i)) -> Foo (x :: i) }
Foo.hs:22:35:
Couldn't match expected type ‘a’ with actual type ‘t0’
because type variable ‘a’ would escape its scope
This (rigid, skolem) type variable is bound by
a pattern with constructor
Hidden :: forall a. Typeable a => Proxy a -> HiddenType,
in a case alternative
at Foo.hs:22:6-24
Relevant bindings include
p :: Proxy a (bound at Foo.hs:22:14)
x :: t0 (bound at Foo.hs:20:8)
In the first argument of ‘Foo’, namely ‘(x :: i)’
In the expression: Foo (x :: i)
Failed, modules loaded: none.
我明白,約束變成共同的論點所以在我看來,這裏的問題是GHC無法處理GADT的模式綁定。如果可以,我可以用一個遞歸讓利給這樣說:
bar :: Foo
bar =
let (x :: i,h) = foo
(Hidden (p::Proxy i)) = h
in Foo x
這應該使範圍的限制,提供額外的參數foo
。我在這裏的目的是使h
包含一些(隱藏)具體類型i
,它應作爲具體類型的多態函數 GHC抱怨:
Foo.hs:19:8:
You cannot bind scoped type variable ‘i’
in a pattern binding signature
In the pattern: x :: i
In the pattern: (x :: i, h)
In a pattern binding:
(x :: i, h) = foo
Foo.hs:20:8:
My brain just exploded
I can't handle pattern bindings for existential or GADT data constructors.
Instead, use a case-expression, or do-notation, to unpack the constructor.
In the pattern: Hidden (p :: Proxy i)
In a pattern binding: (Hidden (p :: Proxy i)) = h
In the expression:
let
(x :: i, h) = foo
(Hidden (p :: Proxy i)) = h
in Foo x
我使用情況下的假設是 1. foo
2.同時計算i
和HiddenType
2.隱藏類型的值涉及(至少部分)第一個元組元素的計算。這意味着我做而不是想在bar
中撥打foo
兩次(一次獲得HiddenType
,並且一次使用該類型綁定第一個元組元素)。 在foo
上存在約束時,是否有某種方法可以使bar
的定義成爲可能?
你究竟想要做什麼?這很少有意義。特別是最後一種情況,你試圖用''Hidden'內部的其他類型來統一類型變量 - 恰恰與你可以用存在類型做什麼相反。第一種情況不起作用,因爲您需要選擇一個實例,以便可以解析'Typeable i'約束,例如'let(x,h)= foo'必須是'let(x,h)= foo: :(Int,HiddenType)',但這不起作用,因爲你不能從'Hidden'內部神奇地產生一個進入。 – user2407038 2014-11-24 05:54:05
你可能試圖實現'Data.Dynamic'嗎? – user2407038 2014-11-24 05:54:23
@ user2407038聽起來很像'Data.Dynamic'。這個例子*真的被切斷了,但是它的核心問題是關於AST中的變量類型。 'foo'就像一個'lambda',其中隱藏類型是變量的(預期)類型。 'bar'就像'let',它需要lambda變量的類型,但是隱藏了那個類型。 – crockeea 2014-11-24 14:20:49