这回答了两种实现问题的方法
1.
使用
reflection
.
使用
Reifies
:
type HasMyType :: forall k. k -> Constraint
type HasMyType name = Reifies name MyType
myFun :: HasMyType name => Proxy name -> String
myFun name = case reflect name of
A -> "Foo"
B -> "Bar"
-- reify :: MyType -> (forall name. HasMyType name => Proxy name -> res) -> res
>> reify A myFun
"Foo"
>> reify B myFun
"Bar"
>> reify A \name -> myFun name
"Foo"
>> reify B \name -> myFun name
"Bar"
Haskell还不能抽象类型变量
\@name -> ..
所以它使用
\(Proxy :: Proxy name) -> ..
.
这个
Proxy
可以从
myFun
哪里
name
提供了可见类型的应用程序,但
reify
仍然会产生
代理
谁的名字必须是“提取的”
{-# Language ScopedTypeVariables #-}
{-# Language TypeApplications #-} ..
myFun :: forall name. HasMyType name => String
myFun = case reflect @name Proxy of
A -> "Foo"
B -> "Bar"
>> reify A \(_ :: _ name) -> myFun @name
"Foo"
>> reify B \(_ :: _ name) -> myFun @name
"Bar"
更简单的选择(
Given
)不依赖类型级别的“名称”来区分不同的字典,因此使用以下警告更危险:
对于每种类型,您应该只给出一个值。如果范围内有多个实例,则行为由实现定义。
type HasMyType :: Constraint
type HasMyType = Given MyType
myFun :: HasMyType => String
myFun = case given of
A -> "Foo"
B -> "Bar"
-- give :: MyType -> (HasMyType => res) -> res
>> give A myFun
"Foo"
>> give B myFun
"Bar"