Skip to content

Instantly share code, notes, and snippets.

@Axure
Last active May 19, 2022 02:53
Show Gist options
  • Save Axure/374cd11bf2957039b96ec57b6a648f2b to your computer and use it in GitHub Desktop.
Save Axure/374cd11bf2957039b96ec57b6a648f2b to your computer and use it in GitHub Desktop.
Type level programming in C++
#include <iostream>
/**
*
def checksum(l: List[Int]): Int = l.reverse.zipWithIndex.map {
case (v, i) => v * (i + 1)
}.sum % 11
def isValid(l: List[Int]): Boolean = l.size == 9 && checksum(l) == 0
isValid(List(3, 4, 5, 8, 8, 2, 8, 6, 5)) // true
isValid(List(3, 1, 5, 8, 8, 2, 8, 6, 5)) // false
*/
#include <functional>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <string>
#include <deque>
#include <numeric>
template<class T, std::size_t level = 1>
class AbstractCollection {
public:
virtual AbstractCollection &insert(T &value) = 0;
virtual AbstractCollection &insert(T &&value) = 0;
public:
virtual std::size_t size() const noexcept = 0;
virtual AbstractCollection &reverse() noexcept = 0;
// virtual AbstractCollection &zipWithIndex() noexcept = 0;
virtual T sum() const noexcept = 0;
virtual std::string toString() const noexcept = 0;
};
template<class T, template<class, std::size_t> class Derived, std::size_t level = 1>
class AbstractCollectionWithMap;
template<class T, template<class, std::size_t> class Derived, std::size_t level>
class AbstractCollectionWithMap: public AbstractCollection<T, level> {
public:
template<class R>
Derived<R, level> map(std::function<R(T)> function) {
return ((Derived<T, level> *) this)->map<R>(function);
}
// virtual Derived<std::pair<std::size_t, T>, level - 1> zipWithIndex() const noexcept = 0;
};
using PairT= std::pair<std::size_t, int>;
PairT add(const PairT &a, const PairT &b) {
return std::make_pair(static_cast<std::size_t>(1), 1);
};
template<class T>
T add(const T &a, const T &b) {
return a + b;
};
std::string singleToString(std::pair<std::size_t, int> v) {
return std::to_string(v.first) + ", " + std::to_string(v.second);
}
template<class T>
std::string singleToString(T v) {
return std::to_string(v);
}
template<class T, std::size_t level = 1>
class List;
template<class T, std::size_t level>
class List: public AbstractCollectionWithMap<T, List, level> {
private:
T value;
std::deque<T> elements;
public:
List() {}
List(List &another) : elements(another.elements) {
}
List(List &&another) : elements(another.elements) {
}
virtual ~List() {}
public:
List &insert(T &value) override {
this->elements.push_back(value);
return *this;
}
List &insert(T &&value) override {
this->elements.push_back(value);
return *this;
}
public:
size_t size() const noexcept override {
return this->elements.size();
}
/**
* A mutable version.
* @return
*/
List &reverse() noexcept override {
std::reverse(this->elements.begin(), this->elements.end());
return *this;
}
List<std::pair<std::size_t, T>, level - 1> zipWithIndex() const noexcept {
List<std::pair<std::size_t, T>, level - 1> res;
for (std::size_t i = 0; i < this->elements.size(); ++i) {
res.insert(std::make_pair(i, this->elements.at(i)));
}
return res;
}
template<class R>
List<R, level> map(std::function<R(T)> function) {
List<R, level> res;
for (auto &element: this->elements) {
res.insert(function(element));
}
return res;
}
T sum() const noexcept override {
T res = T();
for (auto &element: this->elements) {
res = add(element, res);
}
return res;
// return std::accumulate(this->elements.begin(), this->elements.end(), T(), add);
}
std::string toString() const noexcept override {
std::stringstream stringstream;
for (auto &element: this->elements) {
stringstream << singleToString(element) << ", ";
}
return stringstream.str();
}
};
template<class T>
class List<T, 0>: public List<T, 1> {
void zipWithIndex() const noexcept {
}
};
int checkSum(List<int> &l) {
// return 1;
return l
.reverse()
.zipWithIndex()
.map<int>([](std::pair<std::size_t, int> pair) -> int {
return pair.second * (pair.first + 1);
})
.sum() % 11;
}
bool isValid(List<int> &l) {
return (l.size() == 9) && (checkSum(l) == 0);
}
int main() {
std::cout << "Hello, World!" << std::endl;
// List<int> list;
AbstractCollectionWithMap<int, List> *list = new List<int>();
std::cout << list->size() << std::endl;
list->insert(1).insert(2).insert(3);
std::cout << list->size() << std::endl;
std::cout << list->toString() << std::endl;
list->reverse();
std::cout << list->toString() << std::endl;
std::cout << list->sum() << std::endl;
auto res = list->map<int>([](int a) -> int { return 2 + a; });
std::cout << res.sum() << std::endl;
std::cout << checkSum(*dynamic_cast<List<int> *>(list)) << std::endl;
// 0*(0+1) + 1*(1+2) + 2*(2+3) = 13
List<int> list1, list2;
list1
.insert(3)
.insert(4)
.insert(5)
.insert(8)
.insert(8)
.insert(2)
.insert(8)
.insert(6)
.insert(5);
list2
.insert(3)
.insert(1)
.insert(5)
.insert(8)
.insert(8)
.insert(2)
.insert(8)
.insert(6)
.insert(5);
std::cout << list1.size() << ", " << checkSum(list1) << std::endl;
std::cout << list2.size() << ", " << checkSum(list2) << std::endl;
std::cout << list1.size() << ", " << isValid(list1) << std::endl;
std::cout << isValid(list2) << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment