Feel.Analysis.Narrowing.Kinds (feel v0.1.0)

Copy Markdown View Source

The kinds of subject some facts are about, and the subjects that are paths from each name (D-194, D-154).

A read of a name is narrowed by the facts about the paths from it (p after p.age > 5, D-194), and the analyzer asks of the facts around it whether there are any, and which. Looking through all of them for that is a look at the facts of every other name, for each read: in v1.a > 1 and v2.a > 1 and …, with a name for each term, the n-th read looked at n - 1 facts that were not about it, and a chain was quadratic in cheap steps. So the subjects that are paths from a name are kept by the name, and a read looks up its own. They are kept with the facts, and made from those of a chain the way the facts are (Feel.Analysis.Narrowing.combine/5), so a read costs the facts about the name it reads.

A source is what a path starts at: a name ("p" for {:path, "p", ["age"]}), or a local told by the depth of the context that binds it and its name ({2, "a"} for {:local_path, 2, "a", ["age"]}, D-193). The paths of an element of a filter are not kept: nothing reads them as the paths of a source.

Summary

Types

What a path starts at: a name, or a local as {depth of the context that binds it, name}.

t()

The kinds of subject (:name for a variable, and the tag of the others, as Feel.Analysis.Narrowing.subject/0 has them), and the subjects that are paths from each source, as the keys of a map.

Functions

The kinds of no subject at all.

The kinds of the subjects.

Whether the subjects are all of the kinds given (and so of none other).

The subjects that are paths from a source, as the keys of a map, or nil if there are none.

The kinds with the kind of one more subject, and the subject if it is a path from a source.

The kinds of subject, as a sorted list.

The kinds and the paths of both: those of the facts that two sets of facts make when both hold. The side with fewer sources is the one that is walked, so a chain of n terms that is joined to one more is not n steps for it.

Types

source()

@type source() :: Feel.Name.t() | {pos_integer(), Feel.Name.t()}

What a path starts at: a name, or a local as {depth of the context that binds it, name}.

t()

@type t() :: %Feel.Analysis.Narrowing.Kinds{
  kinds: MapSet.t(atom()),
  paths: %{
    optional(source()) => %{optional(Feel.Analysis.Narrowing.subject()) => true}
  }
}

The kinds of subject (:name for a variable, and the tag of the others, as Feel.Analysis.Narrowing.subject/0 has them), and the subjects that are paths from each source, as the keys of a map.

Functions

new()

@spec new() :: t()

The kinds of no subject at all.

iex> Feel.Analysis.Narrowing.Kinds.to_list(Feel.Analysis.Narrowing.Kinds.new())
[]

of_subjects(subjects)

@spec of_subjects(Enumerable.t()) :: t()

The kinds of the subjects.

iex> kinds = Feel.Analysis.Narrowing.Kinds.of_subjects(["x", {:path, "p", ["age"]}, {:path, "p", ["size"]}])
iex> Feel.Analysis.Narrowing.Kinds.to_list(kinds)
[:name, :path]
iex> kinds |> Feel.Analysis.Narrowing.Kinds.paths_from("p") |> Map.keys() |> Enum.sort()
[{:path, "p", ["age"]}, {:path, "p", ["size"]}]
iex> Feel.Analysis.Narrowing.Kinds.paths_from(kinds, "x")
nil

only?(kinds, allowed)

@spec only?(t(), [atom()]) :: boolean()

Whether the subjects are all of the kinds given (and so of none other).

iex> kinds = Feel.Analysis.Narrowing.Kinds.of_subjects(["x", {:path, "p", ["age"]}])
iex> Feel.Analysis.Narrowing.Kinds.only?(kinds, [:name, :path])
true
iex> Feel.Analysis.Narrowing.Kinds.only?(kinds, [:name])
false

paths_from(kinds, source)

@spec paths_from(t(), source()) ::
  %{optional(Feel.Analysis.Narrowing.subject()) => true} | nil

The subjects that are paths from a source, as the keys of a map, or nil if there are none.

put(kinds, subject)

@spec put(t(), Feel.Analysis.Narrowing.subject()) :: t()

The kinds with the kind of one more subject, and the subject if it is a path from a source.

to_list(kinds)

@spec to_list(t()) :: [atom()]

The kinds of subject, as a sorted list.

union(a, b)

@spec union(t(), t()) :: t()

The kinds and the paths of both: those of the facts that two sets of facts make when both hold. The side with fewer sources is the one that is walked, so a chain of n terms that is joined to one more is not n steps for it.

iex> alias Feel.Analysis.Narrowing.Kinds
iex> a = Kinds.of_subjects([{:path, "p", ["age"]}])
iex> b = Kinds.of_subjects(["x", {:path, "p", ["size"]}])
iex> union = Kinds.union(a, b)
iex> {Kinds.to_list(union), union |> Kinds.paths_from("p") |> map_size()}
{[:name, :path], 2}