feat: implement stack
This commit is contained in:
parent
e3ada19976
commit
7885da4e29
6 changed files with 168 additions and 12 deletions
11
manifest.toml
Normal file
11
manifest.toml
Normal file
|
@ -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.40.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86606B75A600BBD05E539EB59FABC6E307EEEA7B1E5865AFB6D980A93BCB2181" },
|
||||
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
|
||||
]
|
||||
|
||||
[requirements]
|
||||
gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }
|
||||
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
|
|
@ -1,5 +0,0 @@
|
|||
import gleam/io
|
||||
|
||||
pub fn main() {
|
||||
io.println("Hello from fortheck!")
|
||||
}
|
4
src/fortheck/error.gleam
Normal file
4
src/fortheck/error.gleam
Normal file
|
@ -0,0 +1,4 @@
|
|||
pub type Error {
|
||||
StackOverflow
|
||||
StackUnderflow
|
||||
}
|
61
src/fortheck/stack.gleam
Normal file
61
src/fortheck/stack.gleam
Normal file
|
@ -0,0 +1,61 @@
|
|||
import fortheck/error.{type Error, StackOverflow, StackUnderflow}
|
||||
import gleam/bool
|
||||
import gleam/list
|
||||
import gleam/result
|
||||
|
||||
pub opaque type Stack(a) {
|
||||
Stack(capacity: Int, length: Int, data: List(a))
|
||||
}
|
||||
|
||||
pub fn new() -> Stack(a) {
|
||||
Stack(131_072, 0, [])
|
||||
}
|
||||
|
||||
pub fn from_list(list: List(a)) -> Result(Stack(a), Error) {
|
||||
list.try_fold(over: list, from: new(), with: push)
|
||||
}
|
||||
|
||||
pub fn to_list(stack: Stack(a)) -> List(a) {
|
||||
list.reverse(stack.data)
|
||||
}
|
||||
|
||||
pub fn push(onto stack: Stack(a), this item: a) -> Result(Stack(a), Error) {
|
||||
use <- bool.guard(
|
||||
when: stack.length >= stack.capacity,
|
||||
return: Error(StackOverflow),
|
||||
)
|
||||
|
||||
Ok(Stack(..stack, length: stack.length + 1, data: [item, ..stack.data]))
|
||||
}
|
||||
|
||||
pub fn pop(from stack: Stack(a)) -> Result(#(a, Stack(a)), Error) {
|
||||
case stack.data {
|
||||
[] -> Error(StackUnderflow)
|
||||
[x, ..xs] -> Ok(#(x, Stack(..stack, length: stack.length - 1, data: xs)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_pop(
|
||||
from stack: Stack(a),
|
||||
apply fun: fn(a, Stack(a)) -> Result(b, Error),
|
||||
) -> Result(b, Error) {
|
||||
use #(item, stack) <- result.try(pop(from: stack))
|
||||
|
||||
fun(item, stack)
|
||||
}
|
||||
|
||||
pub fn pop_2(from stack: Stack(a)) -> Result(#(#(a, a), Stack(a)), Error) {
|
||||
use b, stack <- try_pop(from: stack)
|
||||
use a, stack <- try_pop(from: stack)
|
||||
|
||||
Ok(#(#(a, b), stack))
|
||||
}
|
||||
|
||||
pub fn try_pop_2(
|
||||
from stack: Stack(a),
|
||||
apply fun: fn(a, a, Stack(a)) -> Result(b, Error),
|
||||
) -> Result(b, Error) {
|
||||
use #(#(a, b), stack) <- result.try(pop_2(from: stack))
|
||||
|
||||
fun(a, b, stack)
|
||||
}
|
|
@ -1,12 +1,5 @@
|
|||
import gleeunit
|
||||
import gleeunit/should
|
||||
|
||||
pub fn main() {
|
||||
gleeunit.main()
|
||||
}
|
||||
|
||||
// gleeunit test functions end in `_test`
|
||||
pub fn hello_world_test() {
|
||||
1
|
||||
|> should.equal(1)
|
||||
}
|
||||
|
|
92
test/stack_test.gleam
Normal file
92
test/stack_test.gleam
Normal file
|
@ -0,0 +1,92 @@
|
|||
import fortheck/error
|
||||
import fortheck/stack
|
||||
import gleam/iterator
|
||||
import gleam/pair
|
||||
import gleam/result
|
||||
import gleeunit
|
||||
import gleeunit/should
|
||||
|
||||
pub fn main() {
|
||||
gleeunit.main()
|
||||
}
|
||||
|
||||
pub fn new_test() {
|
||||
stack.new()
|
||||
|> stack.to_list
|
||||
|> should.equal([])
|
||||
}
|
||||
|
||||
pub fn push_test() {
|
||||
stack.new()
|
||||
|> stack.push(123)
|
||||
|> should.be_ok
|
||||
|> stack.push(456)
|
||||
|> should.be_ok
|
||||
|> stack.to_list
|
||||
|> should.equal([123, 456])
|
||||
}
|
||||
|
||||
pub fn push_stack_overflow_test() {
|
||||
iterator.range(1, 131_072)
|
||||
|> iterator.try_fold(stack.new(), stack.push)
|
||||
|> should.be_ok
|
||||
|> stack.push(1)
|
||||
|> should.be_error
|
||||
|> should.equal(error.StackOverflow)
|
||||
}
|
||||
|
||||
pub fn from_list_test() {
|
||||
[123, 456]
|
||||
|> stack.from_list
|
||||
|> should.be_ok
|
||||
|> stack.to_list
|
||||
|> should.equal([123, 456])
|
||||
}
|
||||
|
||||
pub fn pop_stack_underflow_test() {
|
||||
stack.new()
|
||||
|> stack.pop
|
||||
|> should.be_error
|
||||
|> should.equal(error.StackUnderflow)
|
||||
}
|
||||
|
||||
pub fn pop_test() {
|
||||
let assert Ok(stack) = stack.from_list([1, 2, 3])
|
||||
|
||||
stack
|
||||
|> stack.pop
|
||||
|> should.be_ok
|
||||
|> pair.first
|
||||
|> should.equal(3)
|
||||
|
||||
{
|
||||
use a, _ <- stack.try_pop(stack)
|
||||
Ok(a)
|
||||
}
|
||||
|> should.be_ok
|
||||
|> should.equal(3)
|
||||
}
|
||||
|
||||
pub fn pop_2_test() {
|
||||
let assert Ok(stack) = stack.from_list([1, 2, 3])
|
||||
|
||||
stack
|
||||
|> stack.pop_2
|
||||
|> should.be_ok
|
||||
|> pair.first
|
||||
|> should.equal(#(2, 3))
|
||||
|
||||
{
|
||||
use a, b, _ <- stack.try_pop_2(stack)
|
||||
Ok(#(a, b))
|
||||
}
|
||||
|> should.be_ok
|
||||
|> should.equal(#(2, 3))
|
||||
}
|
||||
|
||||
pub fn pop_2_stack_underflow_test() {
|
||||
stack.from_list([1])
|
||||
|> result.try(stack.pop_2)
|
||||
|> should.be_error
|
||||
|> should.equal(error.StackUnderflow)
|
||||
}
|
Loading…
Reference in a new issue