|
| 1 | +export module CppUtils.Functional.LambdaCalculus; |
| 2 | + |
| 3 | +import std; |
| 4 | +import CppUtils.Type.Utility; |
| 5 | + |
| 6 | +export namespace CppUtils::Functional::LambdaCalculus |
| 7 | +{ |
| 8 | + namespace v1 |
| 9 | + { |
| 10 | + inline constexpr auto True = [](auto x) { return [x](auto) { return x; }; }; |
| 11 | + inline constexpr auto False = [](auto) { return [](auto y) { return y; }; }; |
| 12 | + |
| 13 | + static_assert(True(true)(false) == true); |
| 14 | + static_assert(False(true)(false) == false); |
| 15 | + static_assert(std::same_as<std::remove_const_t<decltype(True(True)(False))>, std::remove_const_t<decltype(True)>>); |
| 16 | + static_assert(std::same_as<std::remove_const_t<decltype(False(True)(False))>, std::remove_const_t<decltype(False)>>); |
| 17 | + |
| 18 | + inline constexpr auto If = [](auto condition) { return [condition](auto t) { return [condition, t](auto f) { return condition(t)(f); }; }; }; |
| 19 | + |
| 20 | + static_assert(If(True)(true)(false) == true); |
| 21 | + static_assert(If(False)(true)(false) == false); |
| 22 | + static_assert(std::same_as<std::remove_const_t<decltype(If(True)(True)(False))>, std::remove_const_t<decltype(True)>>); |
| 23 | + static_assert(std::same_as<std::remove_const_t<decltype(If(False)(True)(False))>, std::remove_const_t<decltype(False)>>); |
| 24 | + |
| 25 | + inline constexpr auto And = [](auto lhs, auto rhs) { return If(lhs)(rhs)(False); }; |
| 26 | + |
| 27 | + static_assert(std::same_as<std::remove_const_t<decltype(And(False, False))>, std::remove_const_t<decltype(False)>>); |
| 28 | + static_assert(std::same_as<std::remove_const_t<decltype(And(False, True))>, std::remove_const_t<decltype(False)>>); |
| 29 | + static_assert(std::same_as<std::remove_const_t<decltype(And(True, False))>, std::remove_const_t<decltype(False)>>); |
| 30 | + static_assert(std::same_as<std::remove_const_t<decltype(And(True, True))>, std::remove_const_t<decltype(True)>>); |
| 31 | + |
| 32 | + inline constexpr auto Or = [](auto lhs, auto rhs) { return If(lhs)(True)(rhs); }; |
| 33 | + |
| 34 | + static_assert(std::same_as<std::remove_const_t<decltype(Or(False, False))>, std::remove_const_t<decltype(False)>>); |
| 35 | + static_assert(std::same_as<std::remove_const_t<decltype(Or(False, True))>, std::remove_const_t<decltype(True)>>); |
| 36 | + static_assert(std::same_as<std::remove_const_t<decltype(Or(True, False))>, std::remove_const_t<decltype(True)>>); |
| 37 | + static_assert(std::same_as<std::remove_const_t<decltype(Or(True, True))>, std::remove_const_t<decltype(True)>>); |
| 38 | + |
| 39 | + inline constexpr auto Not = [](auto value) { return If(value)(False)(True); }; |
| 40 | + |
| 41 | + static_assert(std::same_as<std::remove_const_t<decltype(Not(False))>, std::remove_const_t<decltype(True)>>); |
| 42 | + static_assert(std::same_as<std::remove_const_t<decltype(Not(True))>, std::remove_const_t<decltype(False)>>); |
| 43 | + |
| 44 | + static_assert(And(Not(False), Or(True, False))(true)(false) == true); |
| 45 | + static_assert(std::same_as<std::remove_const_t<decltype(And(Not(False), Or(True, False))(True)(False))>, std::remove_const_t<decltype(True)>>); |
| 46 | + |
| 47 | + inline constexpr auto Successor = [](auto n) { return [n](auto f) { return [n, f](auto x) { return f(n(f)(x)); }; }; }; |
| 48 | + inline constexpr auto Zero = False; |
| 49 | + inline constexpr auto Count = [](auto c) { return c + 1; }; |
| 50 | + |
| 51 | + static_assert(not std::same_as<std::remove_const_t<decltype(Successor(Zero))>, std::remove_const_t<decltype(Zero)>>); |
| 52 | + static_assert(Zero(Count)(0uz) == 0uz); |
| 53 | + static_assert(Successor(Zero)(Count)(0uz) == 1uz); |
| 54 | + static_assert(Successor(Successor(Zero))(Count)(0uz) == 2uz); |
| 55 | + |
| 56 | + inline constexpr auto Add = [](auto lhs, auto rhs) { return lhs(Successor)(rhs); }; |
| 57 | + |
| 58 | + static_assert(std::same_as<std::remove_const_t<decltype(Add(Zero, Zero))>, std::remove_const_t<decltype(Zero)>>); |
| 59 | + static_assert(Add(Zero, Zero)(Count)(0uz) == 0uz); |
| 60 | + |
| 61 | + static_assert(std::same_as<std::remove_const_t<decltype(Add(Zero, Successor(Zero)))>, std::remove_const_t<decltype(Successor(Zero))>>); |
| 62 | + static_assert(Add(Zero, Successor(Zero))(Count)(0uz) == 1uz); |
| 63 | + |
| 64 | + static_assert(std::same_as<std::remove_const_t<decltype(Add(Successor(Zero), Successor(Zero)))>, std::remove_const_t<decltype(Successor(Successor(Zero)))>>); |
| 65 | + static_assert(Add(Successor(Zero), Successor(Zero))(Count)(0uz) == 2uz); |
| 66 | + |
| 67 | + inline constexpr auto Mult = [](auto lhs, auto rhs) { return [lhs, rhs](auto f) { return lhs(rhs(f)); }; }; |
| 68 | + |
| 69 | + static_assert(Mult(Successor(Successor(Zero)), Successor(Successor(Zero)))(Count)(0uz) == 4uz); |
| 70 | + } |
| 71 | + |
| 72 | + inline namespace v2 |
| 73 | + { |
| 74 | + template<std::size_t Index> // De Bruijn index |
| 75 | + struct Variable final |
| 76 | + {}; |
| 77 | + |
| 78 | + template<class Body> |
| 79 | + struct Lambda final |
| 80 | + {}; |
| 81 | + |
| 82 | + template<class Function, class Argument> |
| 83 | + struct Application final |
| 84 | + {}; |
| 85 | + |
| 86 | + template<class Expression, class Value, std::size_t Depth> |
| 87 | + struct Substitute final |
| 88 | + { |
| 89 | + using type = Expression; |
| 90 | + }; |
| 91 | + |
| 92 | + template<std::size_t Index, class Value, std::size_t Depth> |
| 93 | + struct Substitute<Variable<Index>, Value, Depth> final |
| 94 | + { |
| 95 | + using type = std::conditional_t<Index == Depth, Value, Variable<Index>>; |
| 96 | + }; |
| 97 | + |
| 98 | + template<class Body, class Value, std::size_t Depth> |
| 99 | + struct Substitute<Lambda<Body>, Value, Depth> final |
| 100 | + { |
| 101 | + using type = Lambda<typename Substitute<Body, Value, Depth + 1>::type>; |
| 102 | + }; |
| 103 | + |
| 104 | + template<class Function, class Argument, class Value, std::size_t Depth> |
| 105 | + struct Substitute<Application<Function, Argument>, Value, Depth> final |
| 106 | + { |
| 107 | + using type = Application< |
| 108 | + typename Substitute<Function, Value, Depth>::type, |
| 109 | + typename Substitute<Argument, Value, Depth>::type>; |
| 110 | + }; |
| 111 | + |
| 112 | + static_assert(std::is_same_v< |
| 113 | + typename Substitute<Variable<0>, Variable<42>, 0>::type, |
| 114 | + Variable<42>>); |
| 115 | + static_assert(std::is_same_v< |
| 116 | + typename Substitute<Lambda<Variable<1>>, Variable<42>, 0>::type, |
| 117 | + Lambda<Variable<42>>>); |
| 118 | + static_assert(std::is_same_v< |
| 119 | + typename Substitute<Lambda<Lambda<Variable<2>>>, Variable<42>, 0>::type, |
| 120 | + Lambda<Lambda<Variable<42>>>>); |
| 121 | + static_assert(std::is_same_v< |
| 122 | + typename Substitute<Application<Lambda<Variable<1>>, Variable<21>>, Variable<42>, 0>::type, |
| 123 | + Application<Lambda<Variable<42>>, |
| 124 | + Variable<21>>>); |
| 125 | + static_assert(std::is_same_v< |
| 126 | + typename Substitute<Application<Lambda<Variable<21>>, Variable<0>>, Variable<42>, 0>::type, |
| 127 | + Application<Lambda<Variable<21>>, |
| 128 | + Variable<42>>>); |
| 129 | + |
| 130 | + template<class Expression> |
| 131 | + struct BetaReduction final |
| 132 | + { |
| 133 | + using type = Expression; |
| 134 | + }; |
| 135 | + |
| 136 | + template<class Body, class Argument> |
| 137 | + struct BetaReduction<Application<Lambda<Body>, Argument>> final |
| 138 | + { |
| 139 | + using type = typename Substitute<Body, Argument, 0>::type; |
| 140 | + }; |
| 141 | + |
| 142 | + template<class Expression, class Argument0, class Argument1> |
| 143 | + struct BetaReduction<Application<Application<Expression, Argument1>, Argument0>> final |
| 144 | + { |
| 145 | + using type = typename BetaReduction<Application<typename BetaReduction<Application<Expression, Argument1>>::type, Argument0>>::type; |
| 146 | + }; |
| 147 | + |
| 148 | + static_assert(std::is_same_v< |
| 149 | + typename BetaReduction<Variable<0>>::type, |
| 150 | + Variable<0>>); |
| 151 | + static_assert(std::is_same_v< |
| 152 | + typename BetaReduction<Lambda<Variable<0>>>::type, |
| 153 | + Lambda<Variable<0>>>); |
| 154 | + static_assert(std::is_same_v< |
| 155 | + typename BetaReduction<Application<Lambda<Variable<0>>, Variable<1>>>::type, // (λa.a)b |
| 156 | + Variable<1> // b |
| 157 | + >); |
| 158 | + static_assert(std::is_same_v< |
| 159 | + typename BetaReduction<Application<Lambda<Variable<1>>, Variable<2>>>::type, // (λa.b)c |
| 160 | + Variable<1> // b |
| 161 | + >); |
| 162 | + |
| 163 | + template<class Expression> |
| 164 | + struct NormalForm final |
| 165 | + { |
| 166 | + private: |
| 167 | + using Reduced = BetaReduction<Expression>::type; |
| 168 | + |
| 169 | + public: |
| 170 | + using type = Type::LazyEvaluationType<not std::is_same_v<Expression, Reduced>, NormalForm, Reduced, std::type_identity<Reduced>>::type; |
| 171 | + }; |
| 172 | + |
| 173 | + template<class Body> |
| 174 | + struct NormalForm<Lambda<Body>> final |
| 175 | + { |
| 176 | + using type = Lambda<typename NormalForm<Body>::type>; |
| 177 | + }; |
| 178 | + |
| 179 | + static_assert(std::is_same_v< |
| 180 | + typename NormalForm<Variable<0>>::type, // a |
| 181 | + Variable<0> // a |
| 182 | + >); |
| 183 | + static_assert(std::is_same_v< |
| 184 | + typename NormalForm<Lambda<Variable<0>>>::type, // λa.a |
| 185 | + Lambda<Variable<0>> // λa.a |
| 186 | + >); |
| 187 | + static_assert(std::is_same_v< |
| 188 | + typename NormalForm<Application<Lambda<Variable<0>>, Variable<1>>>::type, // (λa.a)b |
| 189 | + Variable<1> // b |
| 190 | + >); |
| 191 | + static_assert(std::is_same_v< |
| 192 | + typename NormalForm<Application<Lambda<Variable<1>>, Variable<2>>>::type, // (λa.b)c |
| 193 | + Variable<1> // b |
| 194 | + >); |
| 195 | + |
| 196 | + static_assert(std::is_same_v< |
| 197 | + typename NormalForm<Application<Application<Lambda<Lambda<Variable<1>>>, Variable<2>>, Variable<3>>>::type, // (λb.λa.b)c d |
| 198 | + Variable<2> // c |
| 199 | + >); |
| 200 | + static_assert(std::is_same_v< |
| 201 | + typename NormalForm<Application<Application<Lambda<Lambda<Variable<0>>>, Variable<2>>, Variable<3>>>::type, // (λb.λa.a)c d |
| 202 | + Variable<3> // d |
| 203 | + >); |
| 204 | + static_assert(std::is_same_v< |
| 205 | + typename NormalForm<Application<Lambda<Variable<0>>, Lambda<Lambda<Variable<0>>>>>::type, // (λa.a)(λb.λa.a) |
| 206 | + Lambda<Lambda<Variable<0>>> // λb.λa.a |
| 207 | + >); |
| 208 | + static_assert(std::is_same_v< |
| 209 | + typename NormalForm<Application<Lambda<Variable<0>>, Lambda<Lambda<Variable<1>>>>>::type, // (λa.a)(λb.λa.b) |
| 210 | + Lambda<Lambda<Variable<1>>> // λb.λa.b |
| 211 | + >); |
| 212 | + |
| 213 | + template<class Lhs, class Rhs> |
| 214 | + inline constexpr bool areEqual = std::is_same_v<typename NormalForm<Lhs>::type, typename NormalForm<Rhs>::type>; |
| 215 | + |
| 216 | + static_assert(areEqual<Application<Lambda<Variable<0>>, Variable<1>>, Variable<1>>); // (λa.a)b == b |
| 217 | + static_assert(areEqual<Lambda<Application<Lambda<Variable<0>>, Variable<1>>>, Lambda<Variable<1>>>); // λb.(λa.a)b == λb.b |
| 218 | + |
| 219 | + using False = Lambda<Lambda<Variable<0>>>; // F = λb.λa.a = λba.a |
| 220 | + using True = Lambda<Lambda<Variable<1>>>; // T = λb.λa.b = λba.b |
| 221 | + |
| 222 | + static_assert(not areEqual<True, False>); |
| 223 | + static_assert(areEqual<True, True>); |
| 224 | + static_assert(areEqual<False, False>); |
| 225 | + static_assert(areEqual<True, Lambda<Lambda<Variable<1>>>>); |
| 226 | + static_assert(areEqual<False, Lambda<Lambda<Variable<0>>>>); |
| 227 | + |
| 228 | + // If = λb.λt.λf.b t f = λbtf.b t f |
| 229 | + using If = |
| 230 | + Lambda< |
| 231 | + Lambda< |
| 232 | + Lambda< |
| 233 | + Application< |
| 234 | + Application<Variable<2>, Variable<1>>, |
| 235 | + Variable<0>>>>>; |
| 236 | + |
| 237 | + // If T T F = T T F = T |
| 238 | + // détail: |
| 239 | + // If T T F = (λbtf.b t f)T T F = T T F = (λba.b)(λba.b)(λba.a) = (λa.(λba.b))(λba.a) = λba.b = T |
| 240 | + static_assert(areEqual< |
| 241 | + Application< |
| 242 | + Application< |
| 243 | + Application<If, True>, |
| 244 | + True>, |
| 245 | + False>, |
| 246 | + True>); |
| 247 | + |
| 248 | + // If F T F = F T F = F |
| 249 | + // détail: |
| 250 | + // If F T F = (λbtf.b t f)F T F = F T F = (λba.a)(λba.b)(λba.a) = (λa.a)(λba.a) = λba.a = F |
| 251 | + static_assert(areEqual< |
| 252 | + Application< |
| 253 | + Application< |
| 254 | + Application<If, False>, |
| 255 | + True>, |
| 256 | + False>, |
| 257 | + False>); |
| 258 | + |
| 259 | + // And = λab.If a b F |
| 260 | + using And = |
| 261 | + Lambda< |
| 262 | + Lambda< |
| 263 | + Application< |
| 264 | + Application< |
| 265 | + Application<If, Variable<1>>, |
| 266 | + Variable<0>>, |
| 267 | + False>>>; |
| 268 | + |
| 269 | + static_assert(areEqual<Application<Application<And, False>, False>, False>); // And F F = (λab.If a b F) F F = If F F F = F |
| 270 | + static_assert(areEqual<Application<Application<And, False>, True>, False>); // And F T = (λab.If a b F) F T = If F T F = F |
| 271 | + static_assert(areEqual<Application<Application<And, True>, False>, False>); // And T F = (λab.If a b F) T F = If T F F = F |
| 272 | + static_assert(areEqual<Application<Application<And, True>, True>, True>); // And T T = (λab.If a b F) T T = If T T F = T |
| 273 | + |
| 274 | + // Or = λab.If a T b |
| 275 | + using Or = |
| 276 | + Lambda< |
| 277 | + Lambda< |
| 278 | + Application< |
| 279 | + Application< |
| 280 | + Application<If, Variable<1>>, |
| 281 | + True>, |
| 282 | + Variable<0>>>>; |
| 283 | + |
| 284 | + static_assert(areEqual<Application<Application<Or, False>, False>, False>); // Or F F = (λab.If a T b) F F = If F T F = F |
| 285 | + static_assert(areEqual<Application<Application<Or, False>, True>, True>); // Or F T = (λab.If a T b) F T = If F T T = T |
| 286 | + static_assert(areEqual<Application<Application<Or, True>, False>, True>); // Or T F = (λab.If a T b) T F = If T T F = T |
| 287 | + static_assert(areEqual<Application<Application<Or, True>, True>, True>); // Or T T = (λab.If a T b) T T = If T T T = T |
| 288 | + |
| 289 | + // Not = λa.If a F T |
| 290 | + using Not = |
| 291 | + Lambda< |
| 292 | + Application< |
| 293 | + Application< |
| 294 | + Application<If, Variable<0>>, |
| 295 | + False>, |
| 296 | + True>>; |
| 297 | + |
| 298 | + static_assert(areEqual<Application<Not, False>, True>); // Not F = (λa.If a F T) F = If F F T = T |
| 299 | + static_assert(areEqual<Application<Not, True>, False>); // Not T = (λa.If a F T) T = If T F T = F |
| 300 | + |
| 301 | + template<class Expression> |
| 302 | + struct Evaluate; |
| 303 | + |
| 304 | + template<> |
| 305 | + struct Evaluate<True> |
| 306 | + { |
| 307 | + static constexpr auto value = true; |
| 308 | + }; |
| 309 | + |
| 310 | + template<> |
| 311 | + struct Evaluate<False> |
| 312 | + { |
| 313 | + static constexpr auto value = false; |
| 314 | + }; |
| 315 | + |
| 316 | + using Zero = False; |
| 317 | + static_assert(areEqual<Zero, Lambda<Lambda<Variable<0>>>>); |
| 318 | + /* |
| 319 | + // Successor = λn.λf.λx.f((n f) x) |
| 320 | + using Successor = |
| 321 | + Lambda< |
| 322 | + Lambda< |
| 323 | + Lambda< |
| 324 | + Application< |
| 325 | + Variable<1>, |
| 326 | + Application< |
| 327 | + Application<Variable<2>, Variable<1>>, |
| 328 | + Variable<0>>>>>>; |
| 329 | + |
| 330 | + static_assert(areEqual<Application<Successor, Zero>, Lambda<Lambda<Application<Variable<1>, Variable<0>>>>>); |
| 331 | + |
| 332 | + // Add = λm.λn.λf.λx.m f (n f x) |
| 333 | + using Add = |
| 334 | + Lambda< |
| 335 | + Lambda< |
| 336 | + Lambda< |
| 337 | + Lambda< |
| 338 | + Application< |
| 339 | + Application<Variable<3>, Variable<1>>, |
| 340 | + Application< |
| 341 | + Application<Variable<2>, Variable<1>>, |
| 342 | + Variable<0>>>>>>>; |
| 343 | + static_assert(areEqual< |
| 344 | + Application<Application<Add, Zero>, Zero>, |
| 345 | + Zero>); |
| 346 | + static_assert(areEqual< |
| 347 | + Application<Application<Add, Zero>, Application<Successor, Zero>>, |
| 348 | + Application<Successor, Zero>>); |
| 349 | + static_assert(areEqual< |
| 350 | + Application<Application<Add, Application<Successor, Zero>>, Application<Successor, Zero>>, |
| 351 | + Application<Successor, Application<Successor, Zero>>>); |
| 352 | + |
| 353 | + // Mult = λm.λn.λf. m (n f) |
| 354 | + using Mult = |
| 355 | + Lambda< |
| 356 | + Lambda< |
| 357 | + Lambda< |
| 358 | + Application< |
| 359 | + Variable<2>, |
| 360 | + Application<Variable<1>, Variable<0>>>>>>; |
| 361 | + static_assert(areEqual< |
| 362 | + Application<Application<Mult, Application<Successor, Application<Successor, Zero>>>, Application<Successor, Application<Successor, Zero>>>, |
| 363 | + Application<Successor, Application<Successor, Application<Successor, Application<Successor, Zero>>>>>); // Mult 2 2 = 4 |
| 364 | + */ |
| 365 | + } |
| 366 | +} |
0 commit comments