我尝试使用类型文字,封闭类型系列和一堆不同的东西来建模我自己的枚举类型。 (我知道GHC.Generics
可能是一种更好的方法,但现在我想知道,发生了什么。)
通过反复试验(我不得不承认)我终于到达了这个程序,编译并且有些东西正在工作(基本情况),但递归不是:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilyDependencies #-}
module Wft2 where
import GHC.TypeLits
import GHC.Exts
data Label (l :: Symbol) = Value deriving Eq
instance (KnownSymbol l) => Show (Label (l :: Symbol)) where show = symbolVal
type family Enumerate (a :: [Symbol]) = b | b -> a where
Enumerate '[] = ()
Enumerate '[a] = Label a
Enumerate (a ': b) = Either (Label a) (Enumerate b)
type family CheckEmbedImpl (a :: [Symbol]) (orig :: [Symbol]) (b :: Symbol) where
CheckEmbedImpl '[] orig b = TypeError (ShowType b :<>: Text " not contained in " :<>: ShowType orig)
CheckEmbedImpl (b : rest) orig b = (() :: Constraint)
CheckEmbedImpl (b : rest) orig c = CheckEmbedImpl rest orig c
type family CheckEmbed (a :: [Symbol]) (b :: Symbol) where
CheckEmbed a b = CheckEmbedImpl a a b
class Embed (l :: [Symbol]) (s :: Symbol) where
embed :: (CheckEmbed l s) => Label s -> Enumerate l
instance {-# OVERLAPS #-} (Enumerate '[t] ~ Label t) => Embed '[t] t where embed _ = Value
instance {-# OVERLAPS #-} Embed '[t] s where embed = undefined
instance {-# OVERLAPS #-} (Either (Label a) (Enumerate b) ~ Enumerate (a ': b)) =>
Embed (a ': b) a where embed _ = Left Value
instance {-# OVERLAPS #-} (Either (Label a) (Enumerate b) ~ Enumerate (a ': b),
Embed b t,
CheckEmbed b t) =>
Embed (a ': b) t where embed l = Right (embed l)
做像embed (Value :: Label "abc") :: Enumerate '["abc"])
和
embed (Value :: Label "abc") :: Enumerate '["abcd"])
按预期工作,但embed (Value :: Label "abc") :: Enumerate '["abc", abc2"]
给了我错误,如
*Wft2> embed (Value :: Label "abc") :: Enumerate '["abc", "abcd" ]
<interactive>:13:1: error:
• Couldn't match type ‘Enumerate l0’
with ‘Either (Label "abc") (Label "abcd")’
Expected type: Enumerate '["abc", "abcd"]
Actual type: Enumerate l0
The type variable ‘l0’ is ambiguous
• In the expression:
embed (Value :: Label "abc") :: Enumerate '["abc", "abcd"]
In an equation for ‘it’:
it = embed (Value :: Label "abc") :: Enumerate '["abc", "abcd"]
我认为我的第三个Embed
实例上的类型相等约束应该处理这个问题。为什么GHC不能推断l0 ~ '["abc", "abcd"]
因此
Enumerate l0 ~ Either (Label "abc") (Label "abcd")
?
奖励积分:如果您了解一些教程,尝试做类似的事情并有一些示例,请提供指示。
要注意它是一个内射型家庭,所以不应该责怪类型家庭不是单射的。
答案 0 :(得分:1)
内射型家庭相当新,不是很进化,而且相当多。
请注意,在以下模式中:
Enumerate '[a] = ...
Enumerate (a ': b) = ...
如果b ~ '[]
那么这些模式都匹配,两者之间的选择是模糊的。 (另请注意,虽然b
'[]
Enumerate '["abc", "abcd" ]
中的b
不是'[]
显而易见,但编译器并不是先验地知道这一点 - 这正是它所尝试的证明使用注入性。)
此类型系列仍然通过了注入性检查,因为类型检查器知道它是一个封闭类型系列,并且知道Enumerate l ~ Label "x"
不能是l ~ "x"
或前一个模式匹配。但是,类型家庭的实际评估语义根本不关心类型家庭是开放还是封闭。注入性根本不影响对类型家族的评估;它只允许类型检查器将Enumerate (a ': (b ': c)) = Either (Label a) (Enumerate (b ': c))
之类的约束减少到def find(self,v):
if self.value is None:
return False
if self.value==v:
return (True)
if v<self.value and self.left is not None:
return (self.left.find(v))
if v>self.value and self.right is not None:
return (self.right.find(v))
return False
。
解决方案是将最后一个模式更改为
Active Directory Sites and Services > Sites > Default-First-Site-Name > Servers > MyDCName > NTDS Settings
这使得它显而易见&#39;这不能与前一个重叠。