Generates type specifications for Regular Expressions at compile time allowing Dialyzer to detect type errors.
This library is a work in progress that was inspired by Stephanie Weirich's talk Dependent Types in Haskell at Strange Loop 2017. The design is evolving based on the constraints imposed by Elixir:
- we cannot specify a list of n elements, so we need to return a tuple
- we use
String.t() | nil
to represent a maybe type based on a(...)?
pattern - we generate a map of results with optional and required keys for named captures
- can we pass in a list of parse functions that can be applied to the matches and modify the return type e.g. from
String.t() -> integer()
This library generates the common Regex functions for your regular expression with a type spec. Create a module for your type and use:
defmodule MyApp do
defmodule MMYYDDDD do
use Regex.Spec, regex: ~r/(\d{2})\-(\d{2})\-(\d{4})/
end
IO.inspect(MMYYDDDD.matches?("2020-12-31")) # false
IO.inspect(MMYYDDDD.run("12-31-2020")) # ["12-31-2020", "12", "31", "2020"]
IO.inspect(MMYYDDDD.runt("12-31-2020")) # {"12-31-2020", "12", "31", "2020"}
end
The specification for run/3 is a list of Strings, and we cannot specify a
dependent type such as a list of length 4. Therefore we implement the
normal run
function and also runt
which can be read as run typed or run tuple
which returns a typed tuple.
This library is incomplete, but you can append to your mix.exs deps:
{:regex_spec, "~> 0.21"}
This library uses leex and yecc to compile your regular expression into a tree of capture groups and then into a Dialyzer tuple type specification.
The docs can be found at https://hexdocs.pm/regex_spec.