These are chat archives for boostorg/hana

2nd
Dec 2015
Jason Rice
@ricejasonf
Dec 02 2015 00:30
So I've been trying to warm up to generating several permutations of arbitrarily structured 'messages' based on several tests applied to a spec. I decided to play around with making different implementations of the following psuedo code (from wikipedia :P):
function is_prime(n : integer)
    if n ≤ 1
        return false
    else if n ≤ 3
        return true
    else if n mod 2 = 0 or n mod 3 = 0
        return false
    let i5
    while i×i ≤ n
        if n mod i = 0 or n mod (i + 2) = 0
            return false
        ii + 6
    return true
here is my first attempt with a bunch of nested if_s
#include<boost/hana.hpp>

namespace hana = boost::hana;

constexpr auto if_ = hana::if_;
template<int c>
constexpr auto int_c = hana::int_c<c>;
template<bool c>
constexpr auto bool_c = hana::bool_c<c>;

auto primality_test = [](auto n)
{
  return
    if_(n <= int_c<1>, hana::nothing,
      if_(n <= int_c<3>, hana::just(n),
        if_(n % int_c<2> == int_c<0> || n % int_c<3> == int_c<0>, hana::nothing,
          if_(hana::is_just(hana::while_(
            [&](auto just_i) {
              return hana::maybe(bool_c<false>,
                [&](auto i) {
                  return bool_c<i * i <= n>;
                }, just_i);
            },
            hana::just(int_c<5>),
            [&](auto just_i) {
              return hana::maybe(hana::nothing,
                [&](auto i) {
                  return if_(n % i == int_c<0> || n % (i + int_c<2>) == int_c<0>, hana::nothing,
                    hana::just(i + int_c<6>));
                }, just_i);
            })), hana::just(n), hana::nothing)))); //practically lisp!
};

int main()
{
  static_assert(decltype(primality_test(int_c<1009>)){} == hana::just(int_c<1009>), "");
  static_assert(decltype(primality_test(int_c<1010>)){} == hana::nothing, "");
}
Jason Rice
@ricejasonf
Dec 02 2015 00:37
In my second go, I am working on chaining these conditions instead of nesting. I was going to try to avoid using while_, but it doesn't seem there is any other way without generating all of the possible i values up front in a range or something.
Is while_ the best choice here?
the second one is slighty slower
Jason Rice
@ricejasonf
Dec 02 2015 16:02
oh crap wait
Jason Rice
@ricejasonf
Dec 02 2015 16:20
the test was broken
the builtin that is
Louis Dionne
@ldionne
Dec 02 2015 17:09
@ricejasonf Yes, I think it’s quite nice. I just hope the Clang/libc++ guys will want the patch.

Regarding your primality testing example, here's how I would do it:

#include <boost/hana.hpp>
namespace hana = boost::hana;


constexpr bool is_prime_impl(int n) {
    if (n <= 1)
        return false;
    else if (n <= 3)
        return true;
    else if (n % 2 == 0 or n % 3 == 0)
        return false;

    int i = 5;
    while (i*i <= n) {
        if (n % i == 0 or n % (i + 2) == 0)
            return false;
        i += 6;
    }
    return true;
}

template <typename N>
constexpr auto is_prime(N const&) {
    return hana::bool_c<is_prime_impl(hana::value<N>())>;
}


auto primes = hana::tuple_c<int,
    2,  3,  5,  7, 11, 13, 17, 19, 23, 29,
    31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
    73, 79, 83, 89, 97,101,103,107,109,113,
    127,131,137,139,149,151,157,163,167,173,
    179,181,191,193,197,199,211,223,227,229,
    233,239,241,251,257,263,269,271,277,281,
    283,293,307,311,313,317,331,337,347,349,
    353,359,367,373,379,383,389,397,401,409,
    419,421,431,433,439,443,449,457,461,463,
    467,479,487,491,499
>;

int main() {
    auto integers = hana::make_range(hana::int_c<0>, hana::int_c<100>);
    hana::for_each(integers, [](auto i) {
        static_assert(decltype(hana::contains(primes, i) == is_prime(i)){}, "");
    });
}

For homogeneous problems, it's much easier and much faster to just use constexpr.

Note that hana::contains is quite slow (it could be optimized, at least for hana::types and hana::integral_constants, but it isn’t).
Jason Rice
@ricejasonf
Dec 02 2015 17:35
ha ha.. i guess i was overcomplicating things
or rather it is a contrived use case
Maik Klein
@MaikKlein
Dec 02 2015 22:19

How do you output different error messages?

Pseudo code:

constexpr auto size = hana::size(something);
// (size == 0) => print "Does not contain anything"
// (size > 1) =>print "Contains duplicates"
where "print" would be the compile time error.
Jason Rice
@ricejasonf
Dec 02 2015 22:21
wouldn't static_assert work?
Maik Klein
@MaikKlein
Dec 02 2015 22:22
I could do static_assert(hana::size(s) == hana::size_c<1>, "Something is wrong");
but then I wouldn't know if it i was 0 or bigger then one and checking that seems a bit cumbersome with static_assert
Jason Rice
@ricejasonf
Dec 02 2015 22:23
static_assert(size == 0, "Does not contain anything");
static_assert(size > 1, "Contains duplicates");
This message was deleted
Maik Klein
@MaikKlein
Dec 02 2015 22:24
hm okay I must be tired :d
Jason Rice
@ricejasonf
Dec 02 2015 22:25
Maik Klein
@MaikKlein
Dec 02 2015 22:39

Wait it should work with 1, but should not accept 0 or 2+. size == 0 doesn't work because 1 == 0 will trigger the assert, and static_assert triggers at false not true.

size != 0 doesn't work because it will also trigger at 1+. I could solve this but it would require some boolean shenanigans

Jason Rice
@ricejasonf
Dec 02 2015 22:46
ah right
Maik Klein
@MaikKlein
Dec 02 2015 22:53
    static_assert(size != 0 || size >= 1, "Empty");
    static_assert(size == 1 || size == 0, "More than 1");
Should be what I want, but that seems way too complicated for something so simple
Jason Rice
@ricejasonf
Dec 02 2015 23:21
here is a much, much simpler solution and the good news is it only generates one warning :P
#include<type_traits>

template<int size, typename = void>
struct SizeChecker
{ };

template<int size>
struct SizeChecker<size,
  std::enable_if_t<(size == 0)>>
{
  static_assert(size == 0, "Does not contain anything");
};

template<int size>
struct SizeChecker<size,
  std::enable_if_t<(size > 1)>>
{
  static_assert(size > 1, "Contains duplicates");
};

int main()
{
  constexpr int size = 1;
  SizeChecker<size>{};
}
Maik Klein
@MaikKlein
Dec 02 2015 23:22
haha
Jason Rice
@ricejasonf
Dec 02 2015 23:22
sorry that's all i got
Maik Klein
@MaikKlein
Dec 02 2015 23:22
It appears that I was very confused and you can actually write it like this static_assert( size != 0, "Must not be empty") and static_assert(size <= 1, "Too many")
I think the trigger at false must have confused me somehow
Jason Rice
@ricejasonf
Dec 02 2015 23:25
ah right It would check the second one after asserting that it wasn't 0
Maik Klein
@MaikKlein
Dec 02 2015 23:27
?
Jason Rice
@ricejasonf
Dec 02 2015 23:27
meaning you can't get two failures
Maik Klein
@MaikKlein
Dec 02 2015 23:28
I can only get one failure
Jason Rice
@ricejasonf
Dec 02 2015 23:28
yeah.. nm :)
Maik Klein
@MaikKlein
Dec 02 2015 23:28
because for 0, 0 <= 1 is true
:d