Compare commits

...

3 Commits

Author SHA1 Message Date
Scott Richmond
846a9839d6 add llist fns; fix missing colors bug; filter works on sets; other improvements 2025-06-12 17:50:22 -04:00
Scott Richmond
6ca5c9ae48 add int? 2025-06-12 16:57:23 -04:00
Scott Richmond
fe029573cf add foldr 2025-06-12 16:55:17 -04:00

View File

@ -228,9 +228,26 @@ fn fold {
} }
} }
fn foldr {
"Folds a list, right-associative."
(f as :fn, []) -> []
(f as :fn, xs as :list) -> fold (f, xs, f ())
(f as :fn, [], root) -> []
(f as :fn, xs as :list, root) -> loop (root, first (xs), rest (xs)) with {
(prev, curr, []) -> f (curr, prev)
(prev, curr, remaining) -> recur (
f (curr, prev)
first (remaining)
rest (remaining)
)
}
}
& TODO: optimize these with base :conj! & TODO: optimize these with base :conj!
fn map { fn map {
"Maps a function over a list: returns a new list with elements that are the result of applying the function to each element in the original list. E.g., `map ([1, 2, 3], inc) &=> [2, 3, 4]`." "Maps a function over a list: returns a new list with elements that are the result of applying the function to each element in the original list. E.g., `map ([1, 2, 3], inc) &=> [2, 3, 4]`."
(f as :fn) -> map (f, _)
(f as :fn, xs) -> { (f as :fn, xs) -> {
fn mapper (prev, curr) -> append (prev, f (curr)) fn mapper (prev, curr) -> append (prev, f (curr))
fold (mapper, xs, []) fold (mapper, xs, [])
@ -242,18 +259,21 @@ fn map {
} }
fn filter { fn filter {
"Takes a list and a predicate function, and returns a new list with only the items that produce truthy values when the function is called on them. E.g., `filter ([1, 2, 3, 4], odd?) &=> [1, 3]`." "Takes a list and a predicate function, and returns a new list with only the items that produce truthy values when the function is called on them. E.g., `filter ([1, 2, 3, 4], odd?) &=> [1, 3]`. Also works on sets."
(p? as :fn, xs) -> { (p? as :fn) -> filter(p?, _)
(p? as :fn, xs as list) -> {
fn filterer (filtered, x) -> if p? (x) fn filterer (filtered, x) -> if p? (x)
then append (filtered, x) then append (filtered, x)
else filtered else filtered
fold (filterer, xs, []) fold (filterer, xs, [])
} }
(p? as :fn, xs as :set) -> do xs > list > filter (p?, _) > set
} }
fn keep { fn keep {
"Takes a list and returns a new list with any `nil` values omitted." "Takes a list and returns a new list with any `nil` values omitted."
(xs) -> filter (some?, xs) (xs as :list) -> filter (some?, xs)
(xs as :set) -> filter (some?, xs)
} }
fn append { fn append {
@ -297,6 +317,7 @@ fn contains? {
"Returns true if a set or list contains a value." "Returns true if a set or list contains a value."
(value, s as :set) -> bool (base :get (s, value)) (value, s as :set) -> bool (base :get (s, value))
(value, l as :list) -> contains? (value, set (list)) (value, l as :list) -> contains? (value, set (list))
(key, d as :dict) -> do d > key > some?
} }
fn omit { fn omit {
@ -1031,6 +1052,11 @@ fn round {
(n as :number) -> base :round (n) (n as :number) -> base :round (n)
} }
fn int? {
"Tells if a number is an integer."
(n as :number) -> eq? (n, floor (n))
}
fn range { fn range {
"Returns the set of integers between start (inclusive) and end (exclusive) as a list: [start, end). With one argument, starts at 0. If end is less than start, returns an empty list." "Returns the set of integers between start (inclusive) and end (exclusive) as a list: [start, end). With one argument, starts at 0. If end is less than start, returns an empty list."
(end as :number) -> base :range (0, end) (end as :number) -> base :range (0, end)
@ -1093,6 +1119,7 @@ let colors = #{
:black (0, 0, 0, 255) :black (0, 0, 0, 255)
:silver (192, 192, 192, 255) :silver (192, 192, 192, 255)
:gray (128, 128, 128, 255) :gray (128, 128, 128, 255)
:grey (128, 128, 128, 255)
:white (255, 255, 255, 255) :white (255, 255, 255, 255)
:maroon (128, 0, 0, 255) :maroon (128, 0, 0, 255)
:red (255, 0, 0, 255) :red (255, 0, 0, 255)
@ -1108,6 +1135,8 @@ let colors = #{
:aqua (0, 255, 255, 255) :aqua (0, 255, 255, 255)
} }
let colours = colors
& the initial turtle state & the initial turtle state
let turtle_init = #{ let turtle_init = #{
:position (0, 0) & let's call this the origin for now :position (0, 0) & let's call this the origin for now
@ -1175,12 +1204,13 @@ let pd! = pendown!
fn pencolor! { fn pencolor! {
"Changes the turtle's pen color. Takes a single grayscale value, an rgb tuple, or an rgba tuple. Alias: pc!" "Changes the turtle's pen color. Takes a single grayscale value, an rgb tuple, or an rgba tuple. Alias: pc!"
(color as :keyword) -> add_command! ((:pencolor, color)) (color as :keyword) -> if contains? (colors, color) then add_command! ((:pencolor, color)) else panic! "Ludus doesn't know about the color {color}"
(gray as :number) -> add_command! ((:pencolor, (gray, gray, gray, 255))) (gray as :number) -> add_command! ((:pencolor, (gray, gray, gray, 255)))
((r as :number, g as :number, b as :number)) -> add_command! ((:pencolor, (r, g, b, 255))) ((r as :number, g as :number, b as :number)) -> add_command! ((:pencolor, (r, g, b, 255)))
((r as :number, g as :number, b as :number, a as :number)) -> add_command! ((:pencolor, (r, g, b, a))) ((r as :number, g as :number, b as :number, a as :number)) -> add_command! ((:pencolor, (r, g, b, a)))
} }
let pencolour! = pencolor!
let pc! = pencolor! let pc! = pencolor!
fn penwidth! { fn penwidth! {
@ -1192,7 +1222,7 @@ let pw! = penwidth!
fn background! { fn background! {
"Sets the background color behind the turtle and path. Alias: bg!" "Sets the background color behind the turtle and path. Alias: bg!"
(color as :keyword) -> add_command! ((:background, color)) (color as :keyword) -> if contains? (colors, color) then add_command! ((:background, color)) else panic! "Ludus doesn't know about the color {color}"
(gray as :number) -> add_command! ((:background, (gray, gray, gray, 255))) (gray as :number) -> add_command! ((:background, (gray, gray, gray, 255)))
((r as :number, g as :number, b as :number)) -> add_command! ((:background, (r, g, b, 255))) ((r as :number, g as :number, b as :number)) -> add_command! ((:background, (r, g, b, 255)))
((r as :number, g as :number, b as :number, a as :number)) -> add_command! ((:background, (r, g, b, a))) ((r as :number, g as :number, b as :number, a as :number)) -> add_command! ((:background, (r, g, b, a)))
@ -1301,6 +1331,26 @@ fn penwidth {
() -> do turtle_state > unbox > :penwidth () -> do turtle_state > unbox > :penwidth
} }
fn cons {
"Old-timey lisp `cons`. `Cons`tructs a tuple out of two arguments."
(x, y) -> (x, y)
}
fn car {
"Old-timey lisp `car`. Stands for 'contents of the address register.' Returns the first element in a `cons`ed pair (or any two-tuple)."
((x, _)) -> x
}
fn cdr {
"Old-timey list `cdr`. Stands for 'contents of the decrement register.' Returns the second element in a `cons`ed pair, usually representing the rest of the list."
((_, x)) -> x
}
fn llist {
"Makes an old-timey linked list of its arguments, of LISt Processor fame."
(...xs) -> foldr (cons, xs, nil)
}
box state = nil box state = nil
pkg Prelude { pkg Prelude {
@ -1324,12 +1374,15 @@ pkg Prelude {
bool? & bool bool? & bool
box? & boxes box? & boxes
butlast & lists strings tuples butlast & lists strings tuples
car & llist
cdr & llist
ceil & math ceil & math
chars & strings chars & strings
clear! & turtles clear! & turtles
coll? & dicts lists sets tuples coll? & dicts lists sets tuples
colors & turtles colors & turtles
concat & string list set concat & string list set
cons & llist
contains? & list set contains? & list set
cos & math cos & math
count & string list set tuple dict count & string list set tuple dict
@ -1359,6 +1412,7 @@ pkg Prelude {
floor & math floor & math
fn? & functions fn? & functions
fold & lists fold & lists
foldr & lists
forward! & turtles forward! & turtles
get & dicts get & dicts
goto! & turtles goto! & turtles
@ -1369,6 +1423,7 @@ pkg Prelude {
hideturtle! & turtles hideturtle! & turtles
home! & turtles home! & turtles
inc & math inc & math
int? & math
inv & math inv & math
inv/0 & math inv/0 & math
inv/safe & math inv/safe & math