63
64 type U32 is Data:
65 U32{data: Word(32n)}
66
67 type F32 is Data:
68 F32{data: Word(32n)}
69
70 type Char is Data:
71 Chr{code: U32}
72
73 type String is Data:
74 SNil{}
75 SCon{head: Char, tail: String}
76
77 type Array<-T: Type> is Type:
78 ALeaf{value: T}
79 ANode{xs: Array }
1387
1388 law Word.add_comm.go:
1389 for n: Nat
1390 for a: Word(n)
1391 for b: Word(n)
1392 for c: Bool
1393 {Word.adc(n, a, b, False{}, c) == Word.adc(n, b, a, False{}, c) : Word(n)}
1394
1395 def Word.add_comm.arm(p, at, bt, k, h):
1396 Equal.cong(Word(p), Word(1n+p), w => WCon{h, w},
1397 Word.adc(p, at, bt, False{}, k), Word.adc(p, bt, at, False{}, k),
1398 Word.add_comm.go(p, at, bt, k))
1399
1400 def Word.add_comm.go(n, a, b, c):
1401 match n:
1402 case 0n:
1403 match a b:
1404 case WNil{} WNil{}:
1405 {==}
1406 case 1n+p:
1407 match a b c:
1408 case WCon{False{}, at} WCon{False{}, bt} False{}:
1409 Word.add_comm.arm(p, at, bt, False{}, False{})
1410 case WCon{False{}, at} WCon{False{}, bt} True{}:
1411 Word.add_comm.arm(p, at, bt, False{}, True{})
1412 case WCon{False{}, at} WCon{True{}, bt} False{}:
1413 Word.add_comm.arm(p, at, bt, False{}, True{})
1414 case WCon{False{}, at} WCon{True{}, bt} True{}:
1415 Word.add_comm.arm(p, at, bt, True{}, False{})
1416 case WCon{True{}, at} WCon{False{}, bt} False{}:
1417 Word.add_comm.arm(p, at, bt, False{}, True{})
1418 case WCon{True{}, at} WCon{False{}, bt} True{}:
1419 Word.add_comm.arm(p, at, bt, True{}, False{})
1420 case WCon{True{}, at} WCon{True{}, bt} False{}:
1421 Word.add_comm.arm(p, at, bt, True{}, False{})
1422 case WCon{True{}, at} WCon{True{}, bt} True{}:
1423 Word.add_comm.arm(p, at, bt, True{}, True{})
1424
1425 law Word.add_comm:
1426 for n: Nat
1427 for a: Word(n)
1428 for b: Word(n)
1429 {Word.add(n, a, b) == Word.add(n, b, a) : Word(n)}
1430
1431 def Word.add_comm(n, a, b):
1432 Word.add_comm.go(n, a, b, False{})
1433
1434 def Word.to_nat(n: Nat, w: Word(n)) -> Nat:
1435 match n:
1436 case 0n:
1437 0n
1438 case 1n+p:
1439 match w:
1440 case WCon{False{}, t}:
1441 Nat.double(Word.to_nat(p, t))
1442 case WCon{True{}, t}:
1443 1n+Nat.double(Word.to_nat(p, t))
1444
1445 def Word.mul.go(+n: Nat, m: Nat, a: Word(m), +b: Word(n), acc: Word(n)) ->
1446 Word(n):
1447 match m:
1448 case 0n:
1449 acc
1450 case 1n+mp:
1451 match a:
1452 case WCon{False{}, at}:
1453 Word.mul.go(n, mp, at, Word.shl(n, b), acc)
1454 case WCon{True{}, at}:
1455 Word.mul.go(n, mp, at, Word.shl(n, b), Word.add(n, acc, b))
1456
1457 def Word.mul(+n: Nat, a: Word(n), b: Word(n)) -> Word(n):
1458 Word.mul.go(n, n, a, b, Word.zero(n))
1459
1460 # U32
1461 # ---
1462
1463 def U32.inc(a: U32) -> U32:
1464 match a:
1465 case U32{x}:
1466 U32{Word.inc(32n, x)}
1467
1468 def U32.add(a: U32, b: U32) -> U32:
1469 match a b:
1470 case U32{x} U32{y}:
1471 U32{Word.add(32n, x, y)}
1472
1473 law U32.add_comm:
1474 for a: U32
1475 for b: U32
1476 {U32.add(a, b) == U32.add(b, a) : U32}
1477
1478 def U32.add_comm(a, b):
1479 match a b:
1480 case U32{x} U32{y}:
1481 Equal.cong(Word(32n), U32, w => U32{w}, Word.add(32n, x, y),
1482 Word.add(32n, y, x), Word.add_comm(32n, x, y))
1483
1484 def U32.sub(a: U32, b: U32) -> U32:
1485 match a b:
1486 case U32{x} U32{y}:
1487 U32{Word.sub(32n, x, y)}
1488
1489 def U32.mul(a: U32, b: U32) -> U32:
1490 match a b:
1491 case U32{x} U32{y}:
1492 U32{Word.mul(32n, x, y)}
1493
1494 def U32.not(a: U32) -> U32:
1495 match a:
1496 case U32{x}:
1497 U32{Word.not(32n, x)}
1498
1499 def U32.and(a: U32, b: U32) -> U32:
1500 match a b:
1501 case U32{x} U32{y}:
1502 U32{Word.and(32n, x, y)}
1503
1504 def U32.or(a: U32, b: U32) -> U32:
1505 match a b:
1506 case U32{x} U32{y}:
1507 U32{Word.or(32n, x, y)}
1508
1509 def U32.xor(a: U32, b: U32) -> U32:
1510 match a b:
1511 case U32{x} U32{y}:
1512 U32{Word.xor(32n, x, y)}
1513
1514 def U32.shl(a: U32) -> U32:
1515 match a:
1516 case U32{x}:
1517 U32{Word.shl(32n, x)}
1518
1519 def U32.shr(a: U32) -> U32:
1520 match a:
1521 case U32{x}:
1522 U32{Word.shr(32n, x)}
1523
1524 def U32.shln(a: U32, n: Nat) -> U32:
1525 match n:
1526 case 0n:
1527 a
1528 case 1n+p:
1529 U32.shl(U32.shln(a, p))
1530
1531 def U32.shrn(a: U32, n: Nat) -> U32:
1532 match n:
1533 case 0n:
1534 a
1535 case 1n+p:
1536 U32.shr(U32.shrn(a, p))
1537
1538 def U32.cmp(a: U32, b: U32) -> Cmp:
1539 match a b:
1540 case U32{x} U32{y}:
1541 Word.cmp(32n, x, y)
1542
1543 def U32.is_eq(a: U32, b: U32) -> Bool:
1544 Cmp.is_eq(U32.cmp(a, b))
1545
1546 def U32.is_ne(a: U32, b: U32) -> Bool:
1547 Bool.not(Cmp.is_eq(U32.cmp(a, b)))
1548
1549 def U32.is_lt(a: U32, b: U32) -> Bool:
1550 Cmp.is_lt(U32.cmp(a, b))
1551
1552 def U32.is_le(a: U32, b: U32) -> Bool:
1553 Cmp.is_le(U32.cmp(a, b))
1554
1555 def U32.is_gt(a: U32, b: U32) -> Bool:
1556 Cmp.is_gt(U32.cmp(a, b))
1557
1558 def U32.is_ge(a: U32, b: U32) -> Bool:
1559 Cmp.is_ge(U32.cmp(a, b))
1560
1561 def U32.is_zero(a: U32) -> Bool:
1562 U32.is_eq(a, 0)
1563
1564 def U32.to_nat(a: U32) -> Nat:
1565 match a:
1566 case U32{w}:
1567 Word.to_nat(32n, w)
1568
1569 def U32.from_nat(n: Nat) -> U32:
1570 match n:
1571 case 0n:
1572 0
1573 case 1n+p:
1574 U32.inc(U32.from_nat(p))
1575
1576 def U32.log2.go(+k: Nat, +n: U32, b: Nat) -> Nat:
1577 match k:
1578 case 0n:
1579 b
1580 case 1n+p:
1581 +s = U32.to_nat(U32.shln(1, p))
1582 +t = Nat.mul(s, U32.to_nat(Bool.to_u32(U32.is_ne(U32.shrn(n, s), 0))))
1583 U32.log2.go(p, U32.shrn(n, t), Nat.add(b, t))
1584
1585 def U32.log2(n: U32) -> Nat:
1586 U32.log2.go(5n, n, 0n)
1587
1588 def U32.divmod.go.fin(-p: Nat, q: Word(p), s: U32, b: U32, g: Bool) ->
1589 Word(1n+p) & U32:
1590 match g:
1591 case True{}:
1592 (WCon{True{}, q}, U32.sub(s, b))
1593 case False{}:
1594 (WCon{False{}, q}, s)
1595
1596 def U32.divmod.go.shl(-p: Nat, q: Word(p), +b: U32, ts: Bool & Word(32n)) ->
1597 Word(1n+p) & U32:
1598 (t, s) = ts
1599 +s2 = {U32{s} : U32}
1600 U32.divmod.go.fin(p, q, s2, b, Bool.or(t, U32.is_ge(s2, b)))
1601
1602 def U32.divmod.go.rec(-p: Nat, a0: Bool, +b: U32, qr: Word(p) & U32) ->
1603 Word(1n+p) & U32:
1604 (q, r) = qr
1605 U32{rw} = r
1606 U32.divmod.go.shl(p, q, b, Word.shl.out(32n, a0, rw))
1607
1608 def U32.divmod.go(m: Nat, a: Word(m), +b: U32) -> Word(m) & U32:
1609 match m a:
1610 case 0n WNil{}:
1611 (WNil{}, 0)
1612 case 1n+p WCon{a0, hi}:
1613 U32.divmod.go.rec(p, a0, b, U32.divmod.go(p, hi, b))
1614
1615 def U32.div.fin(qr: Word(32n) & U32) -> U32:
1616 (q, r) = qr
1617 U32{q}
1618
1619 def U32.div.if(aw: Word(32n), b: U32, z: Bool) -> U32:
1620 match z:
1621 case True{}:
1622 0
1623 case False{}:
1624 U32.div.fin(U32.divmod.go(32n, aw, b))
1625
1626 def U32.div(a: U32, b: U32) -> U32:
1627 U32{aw} = a
1628 U32{+bw} = b
1629 U32.div.if(aw, U32{bw}, U32.is_zero(U32{bw}))
1630
1631 def U32.mod.fin(qr: Word(32n) & U32) -> U32:
1632 (q, r) = qr
1633 r
1634
1635 def U32.mod.if(aw: Word(32n), b: U32, z: Bool) -> U32:
1636 match z:
1637 case True{}:
1638 U32{aw}
1639 case False{}:
1640 U32.mod.fin(U32.divmod.go(32n, aw, b))
1641
1642 def U32.mod(a: U32, b: U32) -> U32:
1643 U32{aw} = a
1644 U32{+bw} = b
1645 U32.mod.if(aw, U32{bw}, U32.is_zero(U32{bw}))
1646
1647 def U32.min(a: U32, b: U32) -> U32:
1648 match a b:
1649 case U32{+x} U32{+y}:
1650 Bool.pick(U32, U32.is_lt(U32{x}, U32{y}), U32{x}, U32{y})
1651
1652 def U32.max(a: U32, b: U32) -> U32:
1653 match a b:
1654 case U32{+x} U32{+y}:
1655 Bool.pick(U32, U32.is_lt(U32{x}, U32{y}), U32{y}, U32{x})
1656
1657 def U32.clamp(x: U32, lo: U32, hi: U32) -> U32:
1658 U32.min(U32.max(x, lo), hi)
1659
1660 def U32.pow(+a: U32, n: Nat) -> U32:
1661 match n:
1662 case 0n:
1663 1
1664 case 1n+p:
1665 U32.mul(a, U32.pow(a, p))
1666
1667 def U32.is_even(a: U32) -> Bool:
1668 U32.is_zero(U32.and(a, 1))
1669
1670 # F32
1671 # ---
1672
1673 law U32.to_f32:
1674 for a: U32
1675 F32
1676
1677 law F32.to_u32:
1678 for a: F32
1679 U32
1680
1681 law F32.add:
1682 for a: F32
1683 for b: F32
1684 F32
1685
1686 law F32.sub:
1687 for a: F32
1688 for b: F32
1689 F32
1690
1691 law F32.mul:
1692 for a: F32
1693 for b: F32
1694 F32
1695
1696 law F32.div:
1697 for a: F32
1698 for b: F32
1699 F32
1700
1701 law F32.mod:
1702 for a: F32
1703 for b: F32
1704 F32
1705
1706 law F32.pow:
1707 for a: F32
1708 for b: F32
1709 F32
1710
1711 law F32.atan2:
1712 for a: F32
1713 for b: F32
1714 F32
1715
1716 law F32.neg:
1717 for a: F32
1718 F32
1719
1720 law F32.abs:
1721 for a: F32
1722 F32
1723
1724 law F32.sqrt:
1725 for a: F32
1726 F32
1727
1728 law F32.exp:
1729 for a: F32
1730 F32
1731
1732 law F32.log:
1733 for a: F32
1734 F32
1735
1736 law F32.log2:
1737 for a: F32
1738 F32
1739
1740 law F32.log10:
1741 for a: F32
1742 F32
1743
1744 law F32.sin:
1745 for a: F32
1746 F32
1747
1748 law F32.cos:
1749 for a: F32
1750 F32
1751
1752 law F32.tan:
1753 for a: F32
1754 F32
1755
1756 law F32.asin:
1757 for a: F32
1758 F32
1759
1760 law F32.acos:
1761 for a: F32
1762 F32
1763
1764 law F32.atan:
1765 for a: F32
1766 F32
1767
1768 law F32.sinh:
1769 for a: F32
1770 F32
1771
1772 law F32.cosh:
1773 for a: F32
1774 F32
1775
1776 law F32.tanh:
1777 for a: F32
1778 F32
1779
1780 law F32.floor:
1781 for a: F32
1782 F32
1783
1784 law F32.ceil:
1785 for a: F32
1786 F32
1787
1788 law F32.trunc:
1789 for a: F32
1790 F32
1791
1792 law F32.is_eq:
1793 for a: F32
1794 for b: F32
1795 Bool
1796
1797 law F32.is_ne:
1798 for a: F32
1799 for b: F32
1800 Bool
1801
1802 law F32.is_lt:
1803 for a: F32
1804 for b: F32
1805 Bool
1806
1807 law F32.is_le:
1808 for a: F32
1809 for b: F32
1810 Bool
1811
1812 law F32.is_gt:
1813 for a: F32
1814 for b: F32
1815 Bool
1816
1817 law F32.is_ge:
1818 for a: F32
1819 for b: F32
1820 Bool
1821
1822 law F32.show:
1823 for a: F32
1824 String
1825
1826 law F32.bits:
1827 for a: F32
1828 U32
1829
1830 law F32.read:
1831 for s: String
1832 Maybe<&2, F32>
1833
1834 def F32.min(a: F32, b: F32) -> F32:
1835 match a b:
1836 case F32{+x} F32{+y}:
1837 Bool.pick(F32, F32.is_lt(F32{x}, F32{y}), F32{x}, F32{y})
1838
1839 def F32.max(a: F32, b: F32) -> F32:
1840 match a b:
1841 case F32{+x} F32{+y}:
1842 Bool.pick(F32, F32.is_lt(F32{x}, F32{y}), F32{y}, F32{x})
1843
1844 def F32.clamp(x: F32, lo: F32, hi: F32) -> F32:
1845 F32.min(F32.max(x, lo), hi)
1846
1847 # At t = 0 and t = 1 return that endpoint as is, keeping signed zero and never
1848 # multiplying the other one (an infinite endpoint would give NaN). Between them
1849 # the weighted sum avoids overflowing b - a for finite endpoints of opposite
1850 # signs.
1851 def F32.lerp(a: F32, b: F32, t: F32) -> F32:
1852 match t:
1853 case F32{+z}:
1854 F32.lerp.zero(a, b, F32{z}, F32.is_eq(F32{z}, 0.0))
1855
1856 def F32.lerp.zero(a: F32, b: F32, +t: F32, zero: Bool) -> F32:
1857 match zero:
1858 case True{}:
1859 a
1860 case False{}:
1861 F32.lerp.one(a, b, t, F32.is_eq(t, 1.0))
1862
1863 def F32.lerp.one(a: F32, b: F32, +t: F32, one: Bool) -> F32:
1864 match one:
1865 case True{}:
1866 b
1867 case False{}:
1868 F32.add(F32.mul(a, F32.sub(1.0, t)), F32.mul(b, t))
1869
1870 def F32.square(a: F32) -> F32:
1871 match a:
1872 case F32{+x}:
1873 F32.mul(F32{x}, F32{x})
1874
1875 # Outside [2^-60, 2^60] the squares would overflow or underflow, so scale
1876 # both sides by a power of two first; inside, the scale is 1 and exact.
1877 def F32.hypot(a: F32, b: F32) -> F32:
1878 +x = F32.abs(a)
1879 +y = F32.abs(b)
1880 +m = F32.max(x, y)
1881 +hi = F32.is_gt(m, 1.152921504606847e18)
1882 +lo = F32.is_lt(m, 8.673617379884035e-19)
1883 +s = Bool.pick(F32, hi, 8.470329472543003e-22,
1884 Bool.pick(F32, lo, 1.2676506002282294e30, 1.0))
1885 +u = Bool.pick(F32, hi, 1.1805916207174113e21,
1886 Bool.pick(F32, lo, 7.888609052210118e-31, 1.0))
1887 +p = F32.mul(x, s)
1888 +q = F32.mul(y, s)
1889 F32.mul(F32.sqrt(F32.add(F32.mul(p, p), F32.mul(q, q))), u)
1890
1891 # A rounded zero keeps the input sign, including at the negative half.
1892 def F32.round.zero(a: F32, r: F32, zero: Bool) -> F32:
1893 match zero:
1894 case True{}:
1895 F32.mul(a, 0.0)
1896 case False{}:
1897 r
1898
1899 def F32.round(a: F32) -> F32:
1900 match a:
1901 case F32{+x}:
1902 +f = F32.floor(F32{x})
1903 +r = F32.add(f, Bool.pick(F32, F32.is_ge(F32.sub(F32{x}, f), 0.5), 1.0, 0.0))
1904 F32.round.zero(F32{x}, r, F32.is_eq(r, 0.0))
1905
1906 def F32.pi() -> F32:
1907 3.14159265
1908
1909 def F32.from_nat(n: Nat) -> F32:
1910 U32.to_f32(U32.from_nat(n))
1911
1912 # Preserve the direct cast below 2^32; wider Nats need both word halves.
1913 # Past 2^48-1 no Nat fits, so the direct cast gives 0.
1914 def F32.to_nat.wide(+a: F32, wide: Bool) -> Nat:
1915 match wide:
1916 case False{}:
1917 U32.to_nat(F32.to_u32(a))
1918 case True{}:
1919 +hi = U32.to_nat(F32.to_u32(F32.div(a, 4294967296.0)))
1920 +lo = U32.to_nat(F32.to_u32(F32.mod(a, 4294967296.0)))
1921 Nat.add(Nat.mul(hi, Nat.mul(65536n, 65536n)), lo)
1922
1923 def F32.to_nat(a: F32) -> Nat:
1924 match a:
1925 case F32{+x}:
1926 +wide = Bool.and(F32.is_ge(F32{x}, 4294967296.0),
1927 F32.is_lt(F32{x}, 281474976710656.0))
1928 F32.to_nat.wide(F32{x}, wide)
1929
1930 # Char
1931 # ----
1932
1933 def Char.cmp(a: Char, b: Char) -> (Char & Char) & Cmp:
1934 match a b:
1935 case Chr{+x} Chr{+y}:
1936 ((Chr{x}, Chr{y}), U32.cmp(x, y))
1937
1938 def Char.to_u32(c: Char) -> U32:
1939 match c:
1940 case Chr{x}:
1941 x
1942
1943 def Char.from_u32(x: U32) -> Char:
1944 Chr{x}
1945
1946 def Char.is_eq(a: Char, b: Char) -> Bool:
1947 match a b:
1948 case Chr{x} Chr{y}:
1949 U32.is_eq(x, y)
1950
1951 def Char.is_digit(c: Char) -> Bool:
1952 match c:
1953 case Chr{+x}:
1954 Bool.and(U32.is_ge(x, 48), U32.is_le(x, 57))
1955
1956 def Char.is_upper(c: Char) -> Bool:
1957 match c:
1958 case Chr{+x}:
1959 Bool.and(U32.is_ge(x, 65), U32.is_le(x, 90))
1960
1961 def Char.is_lower(c: Char) -> Bool:
1962 match c:
1963 case Chr{+x}:
1964 Bool.and(U32.is_ge(x, 97), U32.is_le(x, 122))
1965
1966 def Char.is_alpha(+c: Char) -> Bool:
1967 Bool.or(Char.is_upper(c), Char.is_lower(c))
1968
1969 def Char.is_space(c: Char) -> Bool:
1970 match c:
1971 case Chr{+x}:
1972 Bool.or(U32.is_eq(x, 32), Bool.and(U32.is_ge(x, 9), U32.is_le(x, 13)))
1973
1974 def Char.to_upper(c: Char) -> Char:
1975 match c:
1976 case Chr{+x}:
1977 Chr{U32.sub(x, U32.mul(Bool.to_u32(Char.is_lower(Chr{x})), 32))}
1978
1979 def Char.to_lower(c: Char) -> Char:
1980 match c:
1981 case Chr{+x}:
1982 Chr{U32.add(x, U32.mul(Bool.to_u32(Char.is_upper(Chr{x})), 32))}
1983
1984 # String
1985 # ------
1986
1987 def String.append(a: String, b: String) -> String:
1988 match a:
1989 case SNil{}:
1990 b
1991 case SCon{h, t}:
1992 SCon{h, String.append(t, b)}
1993
1994 def String.cmp.rec(h1b: Char, h2b: Char, rr: (String & String) & Cmp) ->
1995 (String & String) & Cmp:
1996 ((t1b, t2b), r) = rr
1997 ((SCon{h1b, t1b}, SCon{h2b, t2b}), r)
1998
1999 law String.cmp:
2000 for a: String
Lines 1-2000 of 3210. More: https://jend.leeeet.dev/read.txt?path=Base/base.bend&start_line=2001
)}
135
136 # Defs
137 # ====
138
139 # Pair
140 # ----
141
142 def Pair(-A: Type, -B: Type) -> Type:
143 Sigma<&1, &1, A, _ => B>
144
145 def Exists(-A: Type, -B: @-x: A -> Type) -> Type:
146 Sigma<&1, &1, A, B>
147
148 def Or(-A: Type, -B: Type) -> Type:
149 Either<&1, &1, A, B>
150
151 def Pair.fst(-A: Type, -B: Type, p: A & B) -> A:
152 (a, b) = p
153 a
154
155 def Pair.snd(-A: Type, -B: Type, p: A & B) -> B:
156 (a, b) = p
157 b
158
159 # Effects
160 # -------
161
162 def IO(-A: Type) -> Type:
163 @-R: Type ->
164 @k: (A -> IO.OP>):
201 import "./effs/args.c"
202 import "./effs/args.js"
203
204 # Runs an argv subprocess on C, Bun and Node, without a shell.
205 # max_output bounds combined stdout/stderr bytes; timeout_ms includes pipe draining.
206 def Process.run(program: String, args: List