~/bend-docscommunity

books.bend source

books.bend on the hub · documented module

import Baseimport ./books_data.bend as Dimport ./books_maps.bend as Mdef char1(+c: Char) -> String:  String.from_list(c <> Nil{})type SpSt is Data:  SpCheck{}  SpDecide{keep: Bool}  SpTake{}def is_alnum(+c: Char) -> Bool:  Bool.or(Char.is_alpha(c), Char.is_digit(c))def strip_spaces_go(fuel: Nat, st: SpSt, rest: String, acc: String) -> String:  match fuel:    case 0n:      acc    case 1n+p:      match st:        case SpCheck{}:          match rest:            case SNil{}:              acc            case SCon{+h, +t}:              strip_spaces_go(p, SpDecide{is_alnum(h)}, rest, acc)        case SpDecide{keep}:          match keep:            case True{}:              strip_spaces_go(p, SpTake{}, rest, acc)            case False{}:              match rest:                case SNil{}:                  acc                case SCon{h, t}:                  strip_spaces_go(p, SpCheck{}, t, acc)        case SpTake{}:          match rest:            case SNil{}:              acc            case SCon{+h, +t}:              strip_spaces_go(p, SpCheck{}, t, String.append(acc, char1(h)))def strip_spaces(+s: String) -> String:  strip_spaces_go(    Nat.add(Nat.mul(3n, String.length(s)), 3n),    SpCheck{},    s,    ""  )def alias_key(+raw: String) -> String:  strip_spaces(String.to_lower(raw))def unmap_str(p: Map<&2, String> & String) -> String:  match p:    case (_, v):      vdef unmap_u32(p: Map<&2, U32> & U32) -> U32:  match p:    case (_, v):      vdef unhas_str(p: Map<&2, String> & Bool) -> Bool:  match p:    case (_, b):      bdef unhas_u32(p: Map<&2, U32> & Bool) -> Bool:  match p:    case (_, b):      bdef map_get_str(+m: Map<&2, String>, +key: String) -> String:  unmap_str(Map.get(String, "", m, key))def map_get_u32(+m: Map<&2, U32>, +key: String) -> U32:  unmap_u32(Map.get(U32, 0, m, key))def map_has_str(+m: Map<&2, String>, +key: String) -> Bool:  unhas_str(Map.has(&2, String, m, key))def map_has_u32(+m: Map<&2, U32>, +key: String) -> Bool:  unhas_u32(Map.has(&2, U32, m, key))def exact_alias_hit(+key: String, hit: Bool) -> Maybe<&2, String>:  match hit:    case False{}:      None{}    case True{}:      Some{map_get_str(M.alias_map(), key)}def exact_alias_nonempty(+key: String, empty: Bool) -> Maybe<&2, String>:  match empty:    case True{}:      None{}    case False{}:      exact_alias_hit(key, map_has_str(M.alias_map(), key))def exact_alias(+key: String) -> Maybe<&2, String>:  exact_alias_nonempty(key, String.is_empty(key))def nat_abs_diff_go(a: Nat, b: Nat, le: Bool) -> Nat:  match le:    case True{}:      Nat.sub(b, a)    case False{}:      Nat.sub(a, b)def nat_abs_diff(+a: Nat, +b: Nat) -> Nat:  nat_abs_diff_go(a, b, Nat.is_le(a, b))# Single recursive one-edit automaton (no mutual recursion)type OePh is Data:  OeGate{over: Bool}  OeBody{}  OeEq{same: Bool}  OeLen{c: Cmp}  OeHoldA{a: String, b: String, ta: String, tb: String, diffs: Nat}def one_edit_go(fuel: Nat, ph: OePh, +a: String, +b: String, +diffs: Nat) -> Bool:  match fuel:    case 0n:      False{}    case 1n+p:      match ph:        case OeGate{over}:          match over:            case True{}:              False{}            case False{}:              one_edit_go(p, OeBody{}, a, b, diffs)        case OeBody{}:          match a b:            case SNil{} SNil{}:              Nat.is_le(diffs, 1n)            case SNil{} SCon{hb, tb}:              one_edit_go(p, OeGate{Nat.is_gt(Nat.add(diffs, 1n), 1n)}, a, tb, Nat.add(diffs, 1n))            case SCon{ha, ta} SNil{}:              one_edit_go(p, OeGate{Nat.is_gt(Nat.add(diffs, 1n), 1n)}, ta, b, Nat.add(diffs, 1n))            case SCon{+ha, +ta} SCon{+hb, +tb}:              one_edit_go(                p,                OeHoldA{SCon{ha, ta}, SCon{hb, tb}, ta, tb, diffs},                SCon{ha, ta},                SCon{hb, tb},                diffs              )        case OeHoldA{+aa, +bb, +ta, +tb, +d0}:          match aa bb:            case SCon{+ha, _} SCon{+hb, _}:              one_edit_go(p, OeEq{Char.is_eq(ha, hb)}, aa, bb, d0)            case _ _:              False{}        case OeEq{same}:          match same:            case True{}:              match a b:                case SCon{ha, ta} SCon{hb, tb}:                  one_edit_go(p, OeBody{}, ta, tb, diffs)                case _ _:                  False{}            case False{}:              one_edit_go(p, OeLen{Nat.cmp(String.length(a), String.length(b))}, a, b, diffs)        case OeLen{c}:          match c:            case EQ{}:              match a b:                case SCon{ha, ta} SCon{hb, tb}:                  one_edit_go(p, OeGate{Nat.is_gt(Nat.add(diffs, 1n), 1n)}, ta, tb, Nat.add(diffs, 1n))                case _ _:                  False{}            case GT{}:              match a:                case SCon{ha, ta}:                  one_edit_go(p, OeGate{Nat.is_gt(Nat.add(diffs, 1n), 1n)}, ta, b, Nat.add(diffs, 1n))                case SNil{}:                  False{}            case LT{}:              match b:                case SCon{hb, tb}:                  one_edit_go(p, OeGate{Nat.is_gt(Nat.add(diffs, 1n), 1n)}, a, tb, Nat.add(diffs, 1n))                case SNil{}:                  False{}def one_edit_apart_go(+a: String, +b: String, far: Bool) -> Bool:  match far:    case True{}:      False{}    case False{}:      one_edit_go(        Nat.add(Nat.mul(4n, Nat.add(String.length(a), String.length(b))), 8n),        OeGate{False{}},        a,        b,        0n      )def one_edit_apart(+a: String, +b: String) -> Bool:  one_edit_apart_go(a, b, Nat.is_gt(nat_abs_diff(String.length(a), String.length(b)), 1n))def first_chars_match(+a: String, +b: String) -> Bool:  match a:    case SNil{}:      False{}    case SCon{+ca, ta}:      match b:        case SNil{}:          False{}        case SCon{+cb, tb}:          Char.is_eq(ca, cb)def starts_digit(s: String) -> Bool:  match s:    case SNil{}:      False{}    case SCon{h, t}:      Char.is_digit(h)def bool_eq(a: Bool, b: Bool) -> Bool:  Cmp.is_eq(Bool.cmp(a, b))type HaSt is Data:  HaCheck{}  HaDecide{is_a: Bool}def has_alpha_go(fuel: Nat, st: HaSt, rest: String) -> Bool:  match fuel:    case 0n:      False{}    case 1n+p:      match st:        case HaCheck{}:          match rest:            case SNil{}:              False{}            case SCon{+h, +t}:              has_alpha_go(p, HaDecide{Char.is_alpha(h)}, t)        case HaDecide{is_a}:          match is_a:            case True{}:              True{}            case False{}:              has_alpha_go(p, HaCheck{}, rest)def has_alpha(+s: String) -> Bool:  has_alpha_go(Nat.add(Nat.mul(2n, String.length(s)), 2n), HaCheck{}, s)def fuzzy_ok_key(+key: String) -> Bool:  Bool.and(Nat.is_ge(String.length(key), 4n), has_alpha(key))type FzPh is Data:  FzScan{}  FzTest{code: String, same_first: Bool, digit_ok: Bool, near: Bool}def fuzzy_find(fuel: Nat, ph: FzPh, xs: List<D.Alias>, +key: String) -> Maybe<&2, String>:  match fuel:    case 0n:      None{}    case 1n+p:      match ph:        case FzScan{}:          match xs:            case Nil{}:              None{}            case D.Alias{+k, c} <> t:              fuzzy_find(                p,                FzTest{                  c,                  first_chars_match(key, k),                  bool_eq(starts_digit(key), starts_digit(k)),                  one_edit_apart(key, k)                },                t,                key              )        case FzTest{+code, same_first, digit_ok, near}:          match same_first:            case False{}:              fuzzy_find(p, FzScan{}, xs, key)            case True{}:              match digit_ok:                case False{}:                  fuzzy_find(p, FzScan{}, xs, key)                case True{}:                  match near:                    case False{}:                      fuzzy_find(p, FzScan{}, xs, key)                    case True{}:                      Some{code}def resolve_fuzzy_go(+key: String, ok: Bool) -> Maybe<&2, String>:  match ok:    case False{}:      None{}    case True{}:      fuzzy_find(600n, FzScan{}, M.fuzzy_alias_table(), key)def resolve_fuzzy(+key: String) -> Maybe<&2, String>:  resolve_fuzzy_go(key, fuzzy_ok_key(key))def resolve_alias_key_go(+key: String, exact: Maybe<&2, String>) -> Maybe<&2, String>:  match exact:    case Some{c}:      Some{c}    case None{}:      resolve_fuzzy(key)def resolve_alias_key(+key: String) -> Maybe<&2, String>:  resolve_alias_key_go(key, exact_alias(key))def resolve_alias(+raw: String) -> Maybe<&2, String>:  resolve_alias_key(alias_key(raw))def chapter_count_go(+book: String, hit: Bool) -> Maybe<&2, U32>:  match hit:    case False{}:      None{}    case True{}:      Some{map_get_u32(M.chapter_map(), book)}def chapter_count(+book: String) -> Maybe<&2, U32>:  chapter_count_go(book, map_has_u32(M.chapter_map(), book))def verse_key(+book: String, +ch: U32) -> String:  String.append(String.append(book, "."), U32.show(ch))def verse_count_go(+key: String, hit: Bool) -> Maybe<&2, U32>:  match hit:    case False{}:      None{}    case True{}:      Some{map_get_u32(M.verse_map(), key)}def verse_count(+book: String, +ch: U32) -> Maybe<&2, U32>:  verse_count_go(verse_key(book, ch), map_has_u32(M.verse_map(), verse_key(book, ch)))def display_name_go(+code: String, hit: Bool) -> String:  match hit:    case False{}:      code    case True{}:      map_get_str(M.name_map(), code)def display_name(+code: String) -> String:  display_name_go(code, map_has_str(M.name_map(), code))def book_names_list() -> List<D.BookName>:  D.book_names()