commit 0831b6c5ec0c51f15bd0d92258dd4bb556b65b32 Author: Yuri Tatishchev Date: Thu Feb 27 16:45:31 2025 -0800 initial commit diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..16a1590 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,23 @@ +name: test + +on: + push: + branches: + - master + - main + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: erlef/setup-beam@v1 + with: + otp-version: "27.1.2" + gleam-version: "1.8.1" + rebar3-version: "3" + # elixir-version: "1" + - run: gleam deps download + - run: gleam test + - run: gleam format --check src test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..55960a5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.beam +*.ez +/build +erl_crash.dump +.idea/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..159992b --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# glemt + +Computational theory automata, work in progress. + +## Development + +```sh +gleam run # Run the project +gleam test # Run the tests +``` diff --git a/gleam.toml b/gleam.toml new file mode 100644 index 0000000..49e9e37 --- /dev/null +++ b/gleam.toml @@ -0,0 +1,19 @@ +name = "glemt" +version = "1.0.0" + +# Fill out these fields if you intend to generate HTML documentation or publish +# your project to the Hex package manager. +# +# description = "" +# licences = ["Apache-2.0"] +# repository = { type = "github", user = "", repo = "" } +# links = [{ title = "Website", href = "" }] +# +# For a full reference of all the available options, you can have a look at +# https://gleam.run/writing-gleam/gleam-toml/. + +[dependencies] +gleam_stdlib = ">= 0.44.0 and < 2.0.0" + +[dev-dependencies] +gleeunit = ">= 1.0.0 and < 2.0.0" diff --git a/manifest.toml b/manifest.toml new file mode 100644 index 0000000..b110e81 --- /dev/null +++ b/manifest.toml @@ -0,0 +1,11 @@ +# This file was generated by Gleam +# You typically do not need to edit this file + +packages = [ + { name = "gleam_stdlib", version = "0.55.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "32D8F4AE03771516950047813A9E359249BD9FBA5C33463FDB7B953D6F8E896B" }, + { name = "gleeunit", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "0E6C83834BA65EDCAAF4FE4FB94AC697D9262D83E6F58A750D63C9F6C8A9D9FF" }, +] + +[requirements] +gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } +gleeunit = { version = ">= 1.0.0 and < 2.0.0" } diff --git a/src/glemt.gleam b/src/glemt.gleam new file mode 100644 index 0000000..d59a8c4 --- /dev/null +++ b/src/glemt.gleam @@ -0,0 +1,65 @@ +import gleam/list +import gleam/string +import gleam/set.{type Set} +import gleam/io + +//pub type State { +// State(Int) +//} + +pub type State = Int + +//pub type AlphabetChar { +// AlphabetChar(String) +//} + +pub type AlphabetChar = String + +pub type NFAError { + NoTransition +} + +pub type NFA { + NFA(states: Set(State), alphabet: Set(AlphabetChar), transition_func: fn(State, AlphabetChar) -> Result(State, NFAError), init_state: State, accepting_states: Set(State)) +} + +//pub type DFAViolation { +// NotAllTransitionsDefined +// MultiplePossibleTransitions +//} + +pub fn check_string(automaton: NFA, input: String) -> Bool { + let result = input + |> string.to_graphemes + |> list.try_fold(automaton.init_state, automaton.transition_func) + + case result { + Ok(state) -> set.contains(automaton.accepting_states, state) + Error(_) -> False + } +} + +pub fn even_a() -> NFA { + let states = set.from_list([0, 1]) + let alphabet = set.from_list(["a"]) + let transition_func = fn (state: State, char: AlphabetChar) -> Result(State, NFAError) { + case state, char { + 0, "a" -> Ok(1) + 1, "a" -> Ok(0) + _, _ -> Error(NoTransition) + } + } + let init_state = 0 + let accepting_states = set.from_list([0]) + NFA(states:, alphabet:, transition_func:, init_state:, accepting_states:) +} + +pub fn main() { + io.println("Hello from glemt!") + + let automaton = even_a() + io.debug(check_string(automaton, "")) + io.debug(check_string(automaton, "a")) + io.debug(check_string(automaton, "aa")) + io.debug(check_string(automaton, "aaab")) +} diff --git a/test/glemt_test.gleam b/test/glemt_test.gleam new file mode 100644 index 0000000..4ba7535 --- /dev/null +++ b/test/glemt_test.gleam @@ -0,0 +1,37 @@ +import glemt +import gleeunit +import gleeunit/should + +pub fn main() { + gleeunit.main() +} + +pub fn nfa_even_a_test() { + glemt.even_a() + |> glemt.check_string("") + |> should.equal(True) + + glemt.even_a() + |> glemt.check_string("a") + |> should.equal(False) + + glemt.even_a() + |> glemt.check_string("aa") + |> should.equal(True) + + glemt.even_a() + |> glemt.check_string("aaa") + |> should.equal(False) + + glemt.even_a() + |> glemt.check_string("aaaa") + |> should.equal(True) + + glemt.even_a() + |> glemt.check_string("aab") + |> should.equal(False) + + glemt.even_a() + |> glemt.check_string("baabaa") + |> should.equal(False) +}