datatype regex { Empty, Lit of string, Cat of (regex, regex), Alt of (regex, regex), Star of regex } datatype 'a list { Empty, Cons of ('a, 'a list) } # Check if a regex matches the null string typecheck nullable? : regex -> bool def nullable? = false | nullable? = string_null? s | nullable? = logical_and (nullable? l) (nullable? r) | nullable? = logical_or (nullable? l) (nullable? r) | nullable? = true # Check if a regex represents the empty language typecheck unsatisfiable? : regex -> bool def unsatisfiable? = true | unsatisfiable? = false | unsatisfiable? = logical_or (unsatisfiable? l) (unsatisfiable? r) | unsatisfiable? = logical_and (unsatisfiable? l) (unsatisfiable? r) | unsatisfiable? = false # Regex derivative with respect to a character typecheck derive : char -> regex -> regex def derive c = Empty | derive c = match string_null? s { case true -> Empty case false -> match equal (string_head s) c { case true -> Lit (string_tail s) case false -> Empty } } | derive c = Alt (derive c l) (derive c r) | derive c = Cat (derive c r) (Star r) | derive c = match nullable? l { case true -> Alt (Cat (derive c l) r) (derive c r) case false -> Cat (derive c l) r } # Let us leverage the regex derivative algorithm to define a regex matcher typecheck match_regex : string -> regex -> bool def match_regex str regex = let def match_regex1 r = nullable? regex | match_regex1 r = match_regex1 cs (derive c cs) in match_regex1 (string_to_list str) regex