She*_*rsh 8 reflection haskell typeclass implicit-parameters
我有一个枚举类型,例如
data MyType = A | B
Run Code Online (Sandbox Code Playgroud)
我希望能够将这种类型的值隐式传递给我的函数。我可以使用ImplicitParams
GHC 扩展来做到这一点:
type HasMyType = (?myType :: MyType)
myFun :: HasMyType => String
myFun = case ?myType of
A -> "Foo"
B -> "Bar"
Run Code Online (Sandbox Code Playgroud)
但是我多次听说,最好使用 Haskell 包反射来完成这项任务。不幸的是,reflection
文档没有解释如何使用库编写类似的代码。弄清楚它并不是那么简单。
所以,我的问题是,是否可以使用该reflection
库来实现类似的代码并满足以下要求?
MyType
应该隐式传递。HasMyType
未指定约束,MyType
则应采用默认值。HasMyType
在一个地方覆盖通过约束传递的值,例如在应用程序的开头。这样的事情可能吗?或者使用reflection
库最接近的近似值是什么?
这回答了实现问题1.使用反射的两种方法。
使用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"
Run Code Online (Sandbox Code Playgroud)
Haskell 还不能抽象类型变量,\@name -> ..
因此它使用\(Proxy :: Proxy name) -> ..
.
可以从可见类型应用程序提供的位置Proxy
删除,但仍然生成其名称必须“提取”的myFun
name
reify
Proxy
{-# 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"
Run Code Online (Sandbox Code Playgroud)
更简单的选项 ( 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"
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
137 次 |
最近记录: |