我有一个枚举类型,例如
data MyType = A | B
Run Code Online (Sandbox Code Playgroud)
我希望能够将这种类型的值隐式传递给我的函数。我可以使用ImplicitParamsGHC 扩展来做到这一点:
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库最接近的近似值是什么?
有没有办法用隐式参数创建函数或使用模板haskell让绑定与隐式参数?
即使用模板haskell生成这样的签名是可能的:
doSomething :: (?context :: Context) => m a
Run Code Online (Sandbox Code Playgroud)
或者像这样的调用:
invoc = let ?context = newContext in doSomething
Run Code Online (Sandbox Code Playgroud)
我找不到合适的代数数据类型,也没有任何函数可以帮助我在模板haskell的API文档中讨论这个主题.我正在使用GHC 7.4.2.
如果模板haskell中没有对此扩展的本机支持,是否还有其他可能在编译期间注入代码(可能类似于模板haskell中的一般"代码注入函数"?).
编辑:我尝试了评论中的建议,这是发生的事情:
runQ [d| f :: (?c :: String) => Int ; f = 7 |]
<interactive>:10:17: parse error on input `c'
Run Code Online (Sandbox Code Playgroud)
这有效:
runQ [d| f :: Int ; f = 7|]
[SigD f_0 (ConT GHC.Types.Int),ValD (VarP f_0) (NormalB (LitE (IntegerL 7))) []]
Run Code Online (Sandbox Code Playgroud)
似乎没有得到支持.
我很好奇Kiselyov和Shan 在" 功能性珍珠:隐式配置"一文中讨论的对隐式参数的反对意见.
在存在隐式参数的情况下内联代码(β-reduce)是不可靠的.
真?我希望GHC应该内联到与传递的隐式参数相同的范围,不是吗?
我相信我理解他们的反对意见:
如果添加,删除或更改其签名,则术语的行为可能会发生变化.
GHC的用户文档解释说,程序员必须注意多态递归和单态限制.这是不是因为内联问题意味着什么?
我假设这个多态递归示例还涵盖了"概括隐含参数"的意思吗?还要别的吗?
Data.Reflection的ReifiesStorable类型类是否真的是解决这些困难的合理解决方案?它似乎每次访问时都会对整个隐式数据结构进行反序列化,这听起来对性能来说是灾难性的.例如,我们可能希望我们的隐含信息是Cayley表或占用ram gig的字符表,并且必须在数百万代数运算期间访问.
是否有一些更好的解决方案采用隐式参数,或者编译器可以在幕后轻松优化的另一种技术,同时仍然通过类型系统使用状态线程或其他保证更多?
我正在定义一些Scala implicits,以便更轻松地使用特定的不可更改的Java类集.下面的Scala代码是一个简单的例子,显然看起来很疯狂,在现实世界中,我试图从Monkey,Tree&Duck中隐含地获取特定资源(而不是数字时代),以便在各种方法中使用purchaseCandles():
// actually 3 Java classes I can not change:
case class Monkey(bananas: Int)
case class Tree(rings: Int)
case class Duck(quacks: Seq[String])
// implicits I created to make my life easier...
implicit def monkey2Age(monkey: Monkey): Int = monkey.bananas / 1000
implicit def tree2Age(tree: Tree): Int = tree.rings
implicit def duck2Age(duck: Duck): Int = duck.quacks.size / 100000
// one of several helper methods that I would like to define only once,
// only useful if they can use …Run Code Online (Sandbox Code Playgroud)