lambda-calculus.test.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. import {
  2. Any_id,
  3. Bool_and,
  4. Bool_false,
  5. Bool_ifThenElse,
  6. Bool_not,
  7. Bool_or,
  8. Bool_true,
  9. Fun2_flip,
  10. GameOfLife_nextGeneration,
  11. List_concat,
  12. List_cons,
  13. List_count,
  14. List_end,
  15. List_filter,
  16. List_flatMap,
  17. List_fold,
  18. List_index,
  19. List_init,
  20. List_map,
  21. List_mapi,
  22. List_natRange,
  23. List_reverse,
  24. Matrix2D_height,
  25. Matrix2D_index,
  26. Matrix2D_init,
  27. Matrix2D_map,
  28. Matrix2D_mapij,
  29. Matrix2D_width,
  30. Nat_add,
  31. Nat_areEqual,
  32. Nat_factorial,
  33. Nat_fibonacci,
  34. Nat_five,
  35. Nat_four,
  36. Nat_isGreater,
  37. Nat_isGreaterOrEqual,
  38. Nat_isLess,
  39. Nat_isLessOrEqual,
  40. Nat_isZero,
  41. Nat_mod,
  42. Nat_mul,
  43. Nat_one,
  44. Nat_pow,
  45. Nat_predOrZero,
  46. Nat_six,
  47. Nat_subOrZero,
  48. Nat_suc,
  49. Nat_three,
  50. Nat_two,
  51. Nat_zero,
  52. Optional_flatMap,
  53. Optional_isNone,
  54. Optional_isSome,
  55. Optional_map,
  56. Optional_none,
  57. Optional_some,
  58. Pair_fst,
  59. Pair_mk,
  60. Pair_snd,
  61. } from "../../src/backend/lambda-calculus.js";
  62. import { assertEquals } from "jsr:@std/assert/assert-equals";
  63. import {
  64. matrixFromNumber2DArray,
  65. toBoolean,
  66. toNullableNumber,
  67. toNumber,
  68. toNumberArray,
  69. toNumberArray2D,
  70. } from "../../src/frontend/lambda-calculus.frontend.ts";
  71. export const assertNumbersEqual = (actual: unknown, expected: number) => {
  72. assertEquals(toNumber(actual), expected);
  73. };
  74. export const assertBooleansEqual = (actual: unknown, expected: boolean) => {
  75. assertEquals(toBoolean(actual), expected);
  76. };
  77. export const assertNullableNumberEqual = (
  78. actual: unknown,
  79. expected: number | null,
  80. ) => {
  81. assertEquals(toNullableNumber(actual), expected);
  82. };
  83. export const assertNumberListEqual = (actual: unknown, expected: number[]) => {
  84. assertEquals(toNumberArray(actual), expected);
  85. };
  86. export const assertNumberList2DEqual = (
  87. actual: unknown,
  88. expected: number[][],
  89. ) => {
  90. assertEquals(toNumberArray2D(actual), expected);
  91. };
  92. Deno.test("Basic arithmetic operations are correct", () => {
  93. assertNumbersEqual(Nat_zero, 0);
  94. assertNumbersEqual(Nat_one, 1);
  95. assertNumbersEqual(Nat_two, 2);
  96. assertNumbersEqual(Nat_suc(Nat_two), 3);
  97. assertNumbersEqual(Nat_suc(Nat_suc(Nat_suc(Nat_two))), 5);
  98. assertNumbersEqual(Nat_add(Nat_two)(Nat_one), 3);
  99. assertNumbersEqual(Nat_mul(Nat_two)(Nat_three), 6);
  100. assertNumbersEqual(Nat_predOrZero(Nat_three), 2);
  101. assertNumbersEqual(Nat_subOrZero(Nat_three)(Nat_two), 1);
  102. assertNumbersEqual(Nat_pow(Nat_two)(Nat_zero), 1);
  103. assertNumbersEqual(Nat_pow(Nat_two)(Nat_one), 2);
  104. assertNumbersEqual(Nat_pow(Nat_two)(Nat_two), 4);
  105. assertNumbersEqual(Nat_pow(Nat_two)(Nat_three), 8);
  106. assertNumbersEqual(Nat_pow(Nat_two)(Nat_four), 16);
  107. assertNumbersEqual(Nat_mod(Nat_five)(Nat_two), 1);
  108. assertNumbersEqual(Nat_mod(Nat_six)(Nat_two), 0);
  109. assertNumbersEqual(Nat_mod(Nat_five)(Nat_three), 2);
  110. });
  111. Deno.test("Basic logical operations are correct", () => {
  112. assertBooleansEqual(Bool_not(Bool_true), false);
  113. assertBooleansEqual(Bool_not(Bool_false), true);
  114. assertBooleansEqual(Bool_and(Bool_false)(Bool_false), false);
  115. assertBooleansEqual(Bool_and(Bool_true)(Bool_false), false);
  116. assertBooleansEqual(Bool_and(Bool_false)(Bool_true), false);
  117. assertBooleansEqual(Bool_and(Bool_true)(Bool_true), true);
  118. assertBooleansEqual(Bool_or(Bool_false)(Bool_false), false);
  119. assertBooleansEqual(Bool_or(Bool_true)(Bool_false), true);
  120. assertBooleansEqual(Bool_or(Bool_false)(Bool_true), true);
  121. assertBooleansEqual(Bool_or(Bool_true)(Bool_true), true);
  122. assertNumbersEqual(Bool_ifThenElse(Bool_true)(Nat_one)(Nat_two), 1);
  123. assertNumbersEqual(Bool_ifThenElse(Bool_false)(Nat_one)(Nat_two), 2);
  124. });
  125. Deno.test("Numbers comparison operations are correct", () => {
  126. assertBooleansEqual(Nat_isZero(Nat_one), false);
  127. assertBooleansEqual(Nat_isZero(Nat_two), false);
  128. assertBooleansEqual(Nat_isZero(Nat_three), false);
  129. assertBooleansEqual(Nat_isZero(Nat_zero), true);
  130. assertBooleansEqual(Nat_isZero(Nat_predOrZero(Nat_one)), true);
  131. assertBooleansEqual(Nat_isGreater(Nat_three)(Nat_two), true);
  132. assertBooleansEqual(Nat_isLess(Nat_three)(Nat_two), false);
  133. assertBooleansEqual(Nat_isGreaterOrEqual(Nat_three)(Nat_two), true);
  134. assertBooleansEqual(Nat_isLessOrEqual(Nat_three)(Nat_two), false);
  135. assertBooleansEqual(Nat_isGreater(Nat_three)(Nat_three), false);
  136. assertBooleansEqual(Nat_isLess(Nat_three)(Nat_three), false);
  137. assertBooleansEqual(Nat_isGreaterOrEqual(Nat_three)(Nat_three), true);
  138. assertBooleansEqual(Nat_isLessOrEqual(Nat_three)(Nat_three), true);
  139. assertBooleansEqual(Nat_areEqual(Nat_zero)(Nat_zero), true);
  140. assertBooleansEqual(Nat_areEqual(Nat_zero)(Nat_one), false);
  141. assertBooleansEqual(Nat_areEqual(Nat_one)(Nat_zero), false);
  142. assertBooleansEqual(Nat_areEqual(Nat_five)(Nat_four), false);
  143. assertBooleansEqual(Nat_areEqual(Nat_three)(Nat_three), true);
  144. });
  145. Deno.test("Pair tuple data type is implemented corectly", () => {
  146. assertNumbersEqual(Pair_fst(Pair_mk(Nat_two)(Nat_three)), 2);
  147. assertNumbersEqual(Pair_snd(Pair_mk(Nat_two)(Nat_three)), 3);
  148. });
  149. Deno.test("Factorial works correctly", () => {
  150. assertNumbersEqual(Nat_factorial(Nat_zero), 1);
  151. assertNumbersEqual(Nat_factorial(Nat_two), 2);
  152. assertNumbersEqual(Nat_factorial(Nat_three), 6);
  153. assertNumbersEqual(Nat_factorial(Nat_four), 24);
  154. assertNumbersEqual(Nat_factorial(Nat_five), 120);
  155. });
  156. Deno.test("Fibonacci works correctly", () => {
  157. assertNumbersEqual(Nat_fibonacci(Nat_zero), 0);
  158. assertNumbersEqual(Nat_fibonacci(Nat_one), 1);
  159. assertNumbersEqual(Nat_fibonacci(Nat_two), 1);
  160. assertNumbersEqual(Nat_fibonacci(Nat_three), 2);
  161. assertNumbersEqual(Nat_fibonacci(Nat_four), 3);
  162. assertNumbersEqual(Nat_fibonacci(Nat_five), 5);
  163. assertNumbersEqual(Nat_fibonacci(Nat_six), 8);
  164. });
  165. Deno.test("Optional type works correctly", () => {
  166. const x1 = Optional_some(Nat_five);
  167. assertNumbersEqual(Pair_fst(x1), 1);
  168. assertNumbersEqual(Pair_snd(x1), 5);
  169. assertNullableNumberEqual(x1, 5);
  170. assertBooleansEqual(Optional_isSome(x1), true);
  171. assertBooleansEqual(Optional_isNone(x1), false);
  172. const x2 = Optional_none;
  173. assertNumbersEqual(Pair_fst(x2), 0);
  174. assertBooleansEqual(Optional_isSome(x2), false);
  175. assertBooleansEqual(Optional_isNone(x2), true);
  176. const x3 = Optional_map(Nat_suc)(x1);
  177. assertNumbersEqual(Pair_fst(x3), 1);
  178. assertNumbersEqual(Pair_snd(x3), 6);
  179. assertNullableNumberEqual(x3, 6);
  180. assertBooleansEqual(Optional_isSome(x3), true);
  181. assertBooleansEqual(Optional_isNone(x3), false);
  182. const x4 = Optional_flatMap((x: unknown) => Optional_some(Nat_suc(x)))(x3);
  183. assertNumbersEqual(Pair_fst(x4), 1);
  184. assertNumbersEqual(Pair_snd(x4), 7);
  185. assertNullableNumberEqual(x4, 7);
  186. assertBooleansEqual(Optional_isSome(x4), true);
  187. assertBooleansEqual(Optional_isNone(x4), false);
  188. const x5 = Optional_flatMap((_x: unknown) => Optional_none)(x4);
  189. assertNumbersEqual(Pair_fst(x5), 0);
  190. assertBooleansEqual(Optional_isSome(x5), false);
  191. assertBooleansEqual(Optional_isNone(x5), true);
  192. const x6 = Optional_map(Nat_suc)(x5);
  193. assertNumbersEqual(Pair_fst(x6), 0);
  194. assertBooleansEqual(Optional_isSome(x6), false);
  195. assertBooleansEqual(Optional_isNone(x6), true);
  196. const x7 = Optional_flatMap((x: unknown) => Optional_some(Nat_suc(x)))(x6);
  197. assertNumbersEqual(Pair_fst(x7), 0);
  198. assertBooleansEqual(Optional_isSome(x7), false);
  199. assertBooleansEqual(Optional_isNone(x7), true);
  200. });
  201. Deno.test("Linked list works correctly", () => {
  202. const x1 = List_cons(Nat_zero)(
  203. List_cons(Nat_one)(
  204. List_cons(Nat_two)(
  205. List_cons(Nat_three)(
  206. List_end,
  207. ),
  208. ),
  209. ),
  210. );
  211. assertNumberListEqual(x1, [0, 1, 2, 3]);
  212. assertNumbersEqual(List_count(x1), 4);
  213. const x2 = List_map(Nat_suc)(x1);
  214. assertNumberListEqual(x2, [1, 2, 3, 4]);
  215. assertNumbersEqual(List_count(x2), 4);
  216. const x3 = List_concat(x1)(x2);
  217. assertNumberListEqual(x3, [0, 1, 2, 3, 1, 2, 3, 4]);
  218. assertNumbersEqual(List_count(x3), 8);
  219. const isEven = (x: unknown) => Nat_areEqual(Nat_mod(x)(Nat_two))(Nat_zero);
  220. const x4 = List_filter(isEven)(x3);
  221. assertNumberListEqual(x4, [0, 2, 2, 4]);
  222. assertNumbersEqual(List_count(x4), 4);
  223. const x5 = List_reverse(x4);
  224. assertNumberListEqual(x5, [4, 2, 2, 0]);
  225. assertNumbersEqual(List_count(x5), 4);
  226. const x6 = List_init(Nat_five)(Any_id);
  227. assertNumberListEqual(x6, [0, 1, 2, 3, 4]);
  228. assertNumbersEqual(List_count(x6), 5);
  229. const elemAndZero = (x: unknown) =>
  230. List_cons(x)(List_cons(Nat_zero)(List_end));
  231. const x7 = List_flatMap(elemAndZero)(x6);
  232. assertNumberListEqual(x7, [0, 0, 1, 0, 2, 0, 3, 0, 4, 0]);
  233. assertNumbersEqual(List_count(x7), 10);
  234. const x7Sum_init = Nat_zero;
  235. const x7Sum_step = (x: unknown) => (acc: unknown) => Nat_add(x)(acc);
  236. const x7Sum = List_fold(x7Sum_init)(x7Sum_step)(x7);
  237. assertNumbersEqual(x7Sum, 10);
  238. const x8 = List_init(Nat_five)((_: unknown) => Nat_zero);
  239. const x9 = List_mapi(Nat_add)(x8);
  240. assertNumberListEqual(x9, [0, 1, 2, 3, 4]);
  241. assertNumbersEqual(List_count(x9), 5);
  242. const x6_0 = List_index(Nat_zero)(x6);
  243. const x6_1 = List_index(Nat_one)(x6);
  244. const x6_2 = List_index(Nat_two)(x6);
  245. const x6_3 = List_index(Nat_three)(x6);
  246. const x6_4 = List_index(Nat_four)(x6);
  247. const x6_5 = List_index(Nat_five)(x6);
  248. const x6_6 = List_index(Nat_six)(x6);
  249. assertNullableNumberEqual(x6_0, 0);
  250. assertNullableNumberEqual(x6_1, 1);
  251. assertNullableNumberEqual(x6_2, 2);
  252. assertNullableNumberEqual(x6_3, 3);
  253. assertNullableNumberEqual(x6_4, 4);
  254. assertNullableNumberEqual(x6_5, null);
  255. assertNullableNumberEqual(x6_6, null);
  256. const x10 = List_natRange(Nat_three)(Nat_six);
  257. assertNumberListEqual(x10, [3, 4, 5, 6]);
  258. });
  259. Deno.test("Matrix work correctly", () => {
  260. const x1 = Matrix2D_init(Nat_three)(Nat_four)(Nat_mul);
  261. assertNumberList2DEqual(x1, [
  262. [0, 0, 0, 0],
  263. [0, 1, 2, 3],
  264. [0, 2, 4, 6],
  265. ]);
  266. const x2 = Matrix2D_map(Nat_suc)(x1);
  267. assertNumberList2DEqual(x2, [
  268. [1, 1, 1, 1],
  269. [1, 2, 3, 4],
  270. [1, 3, 5, 7],
  271. ]);
  272. const x1_0_0 = Matrix2D_index(Nat_zero)(Nat_zero)(x1);
  273. const x1_2_2 = Matrix2D_index(Nat_two)(Nat_two)(x1);
  274. const x1_1_6 = Matrix2D_index(Nat_one)(Nat_six)(x1);
  275. const x1_6_1 = Matrix2D_index(Nat_six)(Nat_one)(x1);
  276. const x1_2_3 = Matrix2D_index(Nat_two)(Nat_three)(x1);
  277. const x1_3_2 = Matrix2D_index(Nat_three)(Nat_two)(x1);
  278. const x3 = Matrix2D_map(Fun2_flip(Nat_pow)(Nat_two))(x2);
  279. assertNumberList2DEqual(x3, [
  280. [1, 1, 1, 1],
  281. [1, 4, 9, 16],
  282. [1, 9, 25, 49],
  283. ]);
  284. assertNullableNumberEqual(x1_0_0, 0);
  285. assertNullableNumberEqual(x1_2_2, 4);
  286. assertNullableNumberEqual(x1_2_3, 6);
  287. assertNullableNumberEqual(x1_3_2, null);
  288. assertNullableNumberEqual(x1_1_6, null);
  289. assertNullableNumberEqual(x1_6_1, null);
  290. const x4 = Matrix2D_init(Nat_three)(Nat_four)((_: unknown) => Nat_zero);
  291. const x5 = Matrix2D_mapij((_: unknown) => (i: unknown) => (j: unknown) =>
  292. Nat_add(i)(j)
  293. )(x4);
  294. assertNumberList2DEqual(x5, [
  295. [0, 1, 2, 3],
  296. [1, 2, 3, 4],
  297. [2, 3, 4, 5],
  298. ]);
  299. assertNumbersEqual(Matrix2D_width(x5), 4);
  300. assertNumbersEqual(Matrix2D_height(x5), 3);
  301. });
  302. Deno.test("Game of life works correctly", () => {
  303. const glider1Matr = [
  304. [0, 0, 0, 0, 0],
  305. [0, 0, 0, 1, 0],
  306. [0, 1, 0, 1, 0],
  307. [0, 0, 1, 1, 0],
  308. [0, 0, 0, 0, 0],
  309. ];
  310. const glider2Matr = [
  311. [0, 0, 0, 0, 0],
  312. [0, 0, 1, 0, 0],
  313. [0, 0, 0, 1, 1],
  314. [0, 0, 1, 1, 0],
  315. [0, 0, 0, 0, 0],
  316. ];
  317. const glider3Matr = [
  318. [0, 0, 0, 0, 0],
  319. [0, 0, 0, 1, 0],
  320. [0, 0, 0, 0, 1],
  321. [0, 0, 1, 1, 1],
  322. [0, 0, 0, 0, 0],
  323. ];
  324. const glider1 = matrixFromNumber2DArray(glider1Matr);
  325. assertNumberList2DEqual(glider1, glider1Matr);
  326. const glider2 = GameOfLife_nextGeneration(glider1);
  327. assertNumberList2DEqual(glider2, glider2Matr);
  328. const glider3 = GameOfLife_nextGeneration(glider2);
  329. assertNumberList2DEqual(glider3, glider3Matr);
  330. const blockMatr = [
  331. [0, 0, 0, 0],
  332. [0, 1, 1, 0],
  333. [0, 1, 1, 0],
  334. [0, 0, 0, 0],
  335. ];
  336. const block1 = matrixFromNumber2DArray(blockMatr);
  337. assertNumberList2DEqual(block1, blockMatr);
  338. const block2 = GameOfLife_nextGeneration(block1);
  339. assertNumberList2DEqual(block2, blockMatr);
  340. const blockMatr2 = [
  341. [1, 1],
  342. [1, 1],
  343. ];
  344. const block3 = matrixFromNumber2DArray(blockMatr2);
  345. assertNumberList2DEqual(block3, blockMatr2);
  346. const block4 = GameOfLife_nextGeneration(block3);
  347. assertNumberList2DEqual(block4, blockMatr2);
  348. });