由于我昨天发布了一个关于Scala中元组的问题的一些有用的答案,我一直在关注Scala HLists。我想从这个问题重新散列一个C ++示例来问另一个:
在C ++中,可以使用模板特化实现编译时递归。我经常在boost元组上进行操作,像Scala / Haskell一样,HLists是通过多次组合通用'cons'类型构建的,每个相关类型一次,并以null_type结束。所以这个:
boost::tuple<int, std::string, float>
在幕后实现:
cons<int, cons<std::string, cons<float, null_type> > >
然后我们可以编写一对在编译时通过此结构递归的函数,当第二个更专用的函数与最终的cons类型匹配时终止。一个简单的例子,计算元素的数量如下所示:
template<typename T1, typename T2>
void countTupleElements( boost::tuples::cons<T1, T2>& tupleRec, int index, const std::vector<std::string>& vals )
{
return 1 + countTupleElements( tupleRec.tail );
}
template<typename T>
void countTupleElements( boost::tuples::cons<T, boost::tuples::null_type>& tupleRec, int index, const std::vector<std::string>& vals )
{
return 1;
}
至关重要的是,这种模式通常用于你想为每种元组元素类型做一些不同的事情(在我的例子中没有说明):在C ++编译时递归是必不可少的,因为一旦代码运行,类型所有有用的信息都会丢失。
我的问题是,与Scala HList类似的东西,例如
val example = 1 :: 2.0 :: "Hello" :: "World" :: HNil
我知道在JVM上运行的Scala具有反射功能 - 因此可以使用运行时递归和使用清单和模式匹配的函数来实现。但我有兴趣知道是否可以使用编译时递归来做类似于C ++示例的操作?
答案 0 :(得分:4)
是的,可以使用隐式参数实现编译时递归。参见:
http://apocalisp.wordpress.com/2010/06/08/type-level-programming-in-scala/
http://jnordenberg.blogspot.com/2008/08/hlist-in-scala.html
答案 1 :(得分:2)
Joshua Suereth在新书Scala in Depth中有一个很好的例子。第7.4节是“使用类型系统的条件执行”,它介绍了HList构造以及如何使用编译时递归来实现可以访问HList的特定元素的IndexedView类型。这用于实现AtIndex类型,用于在编译时检索单个值。
答案 2 :(得分:0)
是的,你可以。请参阅我的博客文章,了解如何在最常见的情况下在Scala的类型系统中实现SKI calculus。我还写过loop unrolling and conditional compilation更具体的案例。最后,solution到这个小puzzle显示了如何实现编译时递归的一种方法的本质。