使用DataKinds
和KindSignatures
,我可以执行以下操作:
data T = T1 | T2 | ... | TN
data D (t :: T) where ...
D1 :: ... -> D t
D2 :: ... -> D t
.
.
.
DN :: ... -> D t
但是,当然,Haskell在运行时删除了这种类型。我可以通过分离构造函数来保留这些信息:
data D' (t :: T) where ...
D1T1 :: ... -> D' T1
D1T2 :: ... -> D' T2
.
.
.
D1TN :: ... -> D' TN
D2T1 :: ... -> D' T1
D2T2 :: ... -> D' T2
.
.
.
D2TN :: ... -> D' TN
.
.
.
DNT1 :: ... -> D' T1
DNT2 :: ... -> D' T2
.
.
.
DNTN :: ... -> D' TN
然后当我模式匹配时,我也得到了这种类型。但是现在我已经把所需的构造数量弄得一团糟,我怀疑这将是一场维护噩梦。
我想做这样的事情:
data DWrap (t :: T) where
DWrap :: t -> D t -> DWrap t
然后我可以对DWrap
进行模式匹配以确定类型:
g :: D T1 -> ...
g = ...
f (DWrap T1 x) = g x
哪个应该没问题,因为一旦我们与T1
匹配,我们就知道t
,然后我们知道它是开始传递给g
的正确类型。
当然,如果我只是想忽略我喜欢的类型:
h :: D t -> ...
h = ...
f (DWrap _ x) = h x
无论哪种方式完整性检查都应该确保我不做任何愚蠢的事情。
除了这种方法不起作用。首先,因为t
不是普通类型*
,所以T
类型T1
。其次'T1
甚至不属于T
类型,它是T2
类型的成员,就像T3
,t
等一样,这样就无法区分不同类型。
要尝试解决第一个问题,我可以将Proxy t
更改为data DWrap (t :: T) where
DWrap :: Proxy t -> D t -> DWrap t
:
data
现在这个Proxy
定义会编译,但这对于区分类型是没有用的,因为data TConstructor (t :: T) where
T1Con :: TConstructor T1
T2Con :: TConstructor T2
.
.
.
TNCon :: TConstructor TN
只有一个构造函数。
我可以这样做:
data DWrap (t :: T) where
DWrap :: TConstructor t -> D t -> DWrap t
然后这个:
g :: D T1 -> ...
g = ...
f (DWrap T1Con x) = g x
然后我可以像这样匹配:
data TConstructor
这应该可以胜任,但我必须写出data T
,这几乎是<input id="uploadBtn" type="file" class="upload" multiple="multiple" name="browsefile" style="display: none !important;"/>
<input type="button" value="ファイル追加" onclick="document.getElementById('uploadBtn').click();" style="float: right;"/>
<input id="filename" type="hidden" />
<br>
<div id="upload_prev"></div>
<div style="clear:both;"></div>
的副本。无论如何,我可以避免这个额外的样板并仍然实现我想要做的事情吗?