{"id":1183,"date":"2015-07-01T22:12:30","date_gmt":"2015-07-02T05:12:30","guid":{"rendered":"http:\/\/www.elbeno.com\/blog\/?p=1183"},"modified":"2015-07-02T07:26:20","modified_gmt":"2015-07-02T14:26:20","slug":"exercising-ranges-part-8","status":"publish","type":"post","link":"https:\/\/www.elbeno.com\/blog\/?p=1183","title":{"rendered":"Exercising Ranges (part 8)"},"content":{"rendered":"<p>(Start at <a href=\"https:\/\/www.elbeno.com\/blog\/?p=1118\">the beginning of the series<\/a> if you want more context.)<\/p>\n<p><strong>Extras from the Haskell Prelude<\/strong><\/p>\n<p>Having implemented <code>iterate<\/code>, there were a couple of other useful things from the Haskell Prelude that I wanted to have available with ranges. First, there&#8217;s <code>cycle<\/code>. It simply takes a finite range and repeats it ad infinitum. The functionality of the cursor is fairly simple, and uses patterns we&#8217;ve already seen, so here it is in its entirety:<\/p>\n<pre lang=\"cpp\">\r\ntemplate <bool IsConst>\r\nstruct cursor\r\n{\r\nprivate:\r\n  template <typename T>\r\n  using constify_if = meta::apply<meta::add_const_if_c<IsConst>, T>;\r\n  using cycle_view_t = constify_if<cycle_view>;\r\n  cycle_view_t *rng_;\r\n  range_iterator_t<constify_if<Rng>> it_;\r\n\r\npublic:\r\n  using single_pass = std::false_type;\r\n  cursor() = default;\r\n  cursor(cycle_view_t &rng)\r\n    : rng_{&rng}\r\n    , it_{begin(rng.r_)}\r\n  {}\r\n  constexpr bool done() const\r\n  {\r\n    return false;\r\n  }\r\n  auto current() const\r\n  RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT\r\n  (\r\n    *it_\r\n  )\r\n  void next()\r\n  {\r\n    if (++it_ == end(rng_->r_))\r\n      it_ = begin(rng_->r_);\r\n  }\r\n  CONCEPT_REQUIRES((bool) BidirectionalRange<Rng>())\r\n  void prev()\r\n  {\r\n    if (it_ == begin(rng_->r_))\r\n      it_ = end(rng_->r_);\r\n    --it_;\r\n  }\r\n  bool equal(cursor const &that) const\r\n  {\r\n    return it_ == that.it_;\r\n  }\r\n};\r\n<\/pre>\n<p>Like all cursors, it implements <code>current()<\/code>, <code>next()<\/code> and <code>equal()<\/code>. Additionally, if the range passed in is bidirectional, so is the cursor, using the <code>CONCEPT_REQUIRES<\/code> macro to conditionally enable <code>prev()<\/code>. There is no sentinel type needed, and the cursor implements <code>done()<\/code> in a way that makes the range infinite.<\/p>\n<p>In Haskell, <code>cycle<\/code> is occasionally useful, although it is often used with <code>zip<\/code> and <code>filter<\/code> to achieve the same effect that <code>stride<\/code> &#8211; a function already provided by the range library &#8211; offers. (I think this combo use of <code>cycle<\/code>, <code>zip<\/code> and <code>filter<\/code> was hinted at briefly in Eric&#8217;s ranges keynote when discussing the motivation that lead to <code>stride<\/code>.) But it&#8217;s sufficiently easy to implement and makes a nice example.<\/p>\n<p><strong>One more from the Prelude<\/strong><\/p>\n<p>A slightly more useful function from the Prelude is <code>scan<\/code> (in Haskell, <code>scanl<\/code> and <code>scanr<\/code>). Despite its somewhat obscure name, it&#8217;s easy to understand: it&#8217;s a fold that returns all the partial results in a sequence. For example:<\/p>\n<pre lang=\"Haskell\">\r\nPrelude> scanl (+) 0 [1,2,3,4]\r\n[0,1,3,6,10]\r\n<\/pre>\n<p>In C++, I&#8217;m not sure what to call this&#8230; perhaps <code>accumulate_partials<\/code>? I left it as scan, for want of a better name. (Edit: It&#8217;s <code>partial_sum<\/code> and it exists in the STL and the ranges library. So I&#8217;ll let this section just stand as a further example.)<\/p>\n<p>One immediate thing to notice about <code>scan<\/code> is that the range it produces is one element longer than the input range. That&#8217;s easily done:<\/p>\n<pre lang=\"cpp\">\r\nnamespace detail\r\n{\r\n  template<typename C>\r\n  using scan_cardinality =\r\n    std::integral_constant<cardinality,\r\n      C::value == infinite ?\r\n        infinite :\r\n        C::value == unknown ?\r\n          unknown :\r\n          C::value >= 0 ?\r\n            static_cast<ranges::cardinality>(C::value + 1) :\r\n            finite>;\r\n} \/\/ namespace detail\r\n<\/pre>\n<p>In general, the action of the cursor is going to be the same as we saw with <code>iterate<\/code>: keep a cached value that is updated with a call to <code>next()<\/code>, and return it with a call to <code>current()<\/code>.<\/p>\n<p><strong>A nice addition to accumulate<\/strong><\/p>\n<p>Eric made a nice addition to the range version of <code>accumulate<\/code> which I also used for <code>scan<\/code>: in addition to the binary operation and the initial value, there is the option of a projection function which will transform the input values before passing them to the binary operation. So when <code>next()<\/code> updates the cached value, that code looks like this:<\/p>\n<pre lang=\"cpp\">\r\nvoid update_value()\r\n{\r\n  val_ = rng_->op_(val_, rng_->proj_(*it_));\r\n}\r\n<\/pre>\n<p>It&#8217;s like having <code>transform<\/code> built in instead of having to do it in a separate step: a nice convenience. And that&#8217;s all there is to <code>scan<\/code>.<\/p>\n<p><strong>Conclusions<\/strong><\/p>\n<p>This has been a fun series of experiments with ranges, and I&#8217;ve learned a lot. I&#8217;ve made mistakes along the way, and I&#8217;m sure there are still parts of my code that reflect extant misunderstandings and general lack of polish. But as an experiment, this has been a success. The code works. As a user of the ranges library with some functional programming experience, it wasn&#8217;t too hard to put together solutions. And the Concept messages really helped, along with a knowledge transfer of iterator categories from the STL.<\/p>\n<p>As an extender of the library adding my own views, it took a little effort to establish correct assumptions and understandings, but Eric&#8217;s code is clear and offers good patterns to build from. I&#8217;m sure a little documentation would have steered me more quickly out of problem areas that I encountered. There are some things that are still problematic and I&#8217;m not yet sure how to tackle: chiefly involving recursion. And at the moment, Concept messages don&#8217;t always help &#8211; I think digging into compiler diagnostics is going to be a fact of life as a range implementer.<\/p>\n<p>C++ will never be as syntactically nice as Haskell is, but ranges offer our best chance yet at high-performance, composable, declarative, correct-by-construction code.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(Start at the beginning of the series if you want more context.) Extras from the Haskell Prelude Having implemented iterate, there were a couple of other useful things from the Haskell Prelude that I wanted to have available with ranges. First, there&#8217;s cycle. It simply takes a finite range and&#8230;<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[22,8],"tags":[],"class_list":["post-1183","post","type-post","status-publish","format-standard","hentry","category-cpp","category-programming"],"_links":{"self":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1183","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1183"}],"version-history":[{"count":4,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1183\/revisions"}],"predecessor-version":[{"id":1197,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1183\/revisions\/1197"}],"wp:attachment":[{"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1183"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1183"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.elbeno.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1183"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}