Last active
May 19, 2022 02:53
-
-
Save Axure/374cd11bf2957039b96ec57b6a648f2b to your computer and use it in GitHub Desktop.
Type level programming in C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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