From 8c802f2a15eab96e885b42771c7fb218f7c28535 Mon Sep 17 00:00:00 2001 From: Jesse Brault Date: Fri, 1 Aug 2025 07:47:56 -0500 Subject: [PATCH] Sketching July 2025. --- sketching/july_2025/closure.dm | 22 +++++++ sketching/july_2025/hkt.dm | 32 ++++++++++ sketching/july_2025/int.dm | 14 +++++ sketching/july_2025/name_one.dm | 39 ++++++++++++ sketching/july_2025/string.dm | 105 ++++++++++++++++++++++++++++++++ sketching/july_2025/trait.dm | 41 +++++++++++++ 6 files changed, 253 insertions(+) create mode 100644 sketching/july_2025/closure.dm create mode 100644 sketching/july_2025/hkt.dm create mode 100644 sketching/july_2025/int.dm create mode 100644 sketching/july_2025/name_one.dm create mode 100644 sketching/july_2025/string.dm create mode 100644 sketching/july_2025/trait.dm diff --git a/sketching/july_2025/closure.dm b/sketching/july_2025/closure.dm new file mode 100644 index 0000000..86279c7 --- /dev/null +++ b/sketching/july_2025/closure.dm @@ -0,0 +1,22 @@ +fn main() + var x = 42 + let cl = { i: Int -> + let result = x + i + x += 1 + result + } + println cl(0) // 42 + println cl(0) // 43 + println cl(0) // 44 +end + +fn main() + var x = 42 + fn cl(i: Int): Int + let result = x + 1 + x += 1 + result + end + println cl(0) // 42 + println cl(1) // 42 +end diff --git a/sketching/july_2025/hkt.dm b/sketching/july_2025/hkt.dm new file mode 100644 index 0000000..6e3bc76 --- /dev/null +++ b/sketching/july_2025/hkt.dm @@ -0,0 +1,32 @@ +pub hkt Functor[Self] + fn map(f: fn (t: T) -> U) -> Self +end + +pub int Iterable + fn iter() -> Iterator +end + +pub int Iterator = () -> Option + +pub enum Option : Functor[Self] + Some(T), + None; + + fn unwrap() -> T + self is Some(t) ? t : throw Exception('Empty Option') + end + + fn expect(msg: String) -> T + self is Some(t) ? t : throw Exception(msg) + end + + impl Functor + fn map(f: fn (t: T) -> U) -> Self + self is Some(t) ? Some(f(t)) : None + end + end + + static fn lift(t: T) -> Self + Some(t) + end +end \ No newline at end of file diff --git a/sketching/july_2025/int.dm b/sketching/july_2025/int.dm new file mode 100644 index 0000000..8e211dc --- /dev/null +++ b/sketching/july_2025/int.dm @@ -0,0 +1,14 @@ +int Greeter + fn greet(): Void +end + +class MyGreeter(greeting: String) : Greeter + impl fn greet() + println greeting + end +end + +fn main() + let g: Greeter = MyGreeter("Hello, World!") + g.greet() +end \ No newline at end of file diff --git a/sketching/july_2025/name_one.dm b/sketching/july_2025/name_one.dm new file mode 100644 index 0000000..fc20753 --- /dev/null +++ b/sketching/july_2025/name_one.dm @@ -0,0 +1,39 @@ +fn main(args: Array) + if args[0] == 'greet' then + println 'Hello!' + end +end + +fn main(args: Array) + args.each { println it } +end + +fn main(args: Array) + if args.find { it == 'greet' } then + println 'There was a greet arg' + end +end + +// longer +fn main(args: Array) + let findIndexResult: Option = args.findIndex { it == 'greet' } + if findIndexResult.isSome() then + let index: Int = findIndex.unwrap() + println "greet arg was index ${index}" + end +end + +// shorter with destructuring +fn main(args: Array) + if let Some(greetIndex) = args.findIndex { it == 'greet' } then + println "greet arg was index ${greetIndex}" + end +end + +fn main(args: Array) + let parsed: CliArgs = std::cli::parse(args) + let greetingCount = parsed.get::('--count', '-c').orElse(1) + if let Some(greeting) = parsed.get('greeting', 'g') then + greetingCount.times { println greeting } + end +end diff --git a/sketching/july_2025/string.dm b/sketching/july_2025/string.dm new file mode 100644 index 0000000..0a7533d --- /dev/null +++ b/sketching/july_2025/string.dm @@ -0,0 +1,105 @@ +pub int Display + fn toString() -> String +end + +pub int LazyDisplay + fn toLazyString() -> DString +end + +pub int DString : Display + parts: Array +end + +pub enum DStringPart + Constant(String), + Display(Display), + Lazy(Fn) +end + +#internal +class DStringImpl(parts) : DString + cachedEval: Option + canCache: Option + + fn getCanCache() -> Boolean + for part in parts do + if part is Lazy then return false end + end + true + end + + impl Display + pub fn toString() -> String + if cachedEval is Some(s) then + return s + end + if canCache is None then + canCache = Some(getCanCache()) + end + // Note the groovy-like property getter + if canCache.truthy then + cachedEval = Some( + parts.reduce('') { acc, part -> + let partAsString = match part as + Constant(s) => s, + Display(d) => d.toString(), + Lazy(f) => throw DumbProgrammerException( + 'Cannot cache when parts contains a Lazy.' + ) + end + acc + partAsString + } + ) + cachedEval.unwrap() + else + parts.reduce('') { acc, part -> + let partAsString = match part as + Constant(s) => s, + Display(d) => d.toString(), + Lazy(f) => f().toString() + end + acc + partAsString + } + end + end + end +end + +// Special "extension" implementation of Option for all T where T : Boolean +pub int HasTruth + fn isTruthy() -> Boolean +end + +impl HasTruth for Option where T is Boolean + pub fn isTruthy() -> Boolean + self is Some(b) ? b : false + end +end + +// some other file +use std::extensions::HasTruth[Option] + +fn maybeSomeOrNone -> Option + Some(true) +end + +fn main() + let o = maybeSomeOrNone() + if o.truthy then + println "It's truthy!" + else + println "It's falsy..." + end +end + +fn stringDemo() -> Void + let plain = 'Hello, World!' + let x = 42 + let withDisplay = "Hello! x is $x" + let withLazy = "Hello! x is ${ x + 42 }" + println plain // Hello, World! + println withDisplay // Hello! x is 42 + println withLazy // Hello! x is 84 + x += 42 + println withLazy // Hello! x is 126 +end \ No newline at end of file diff --git a/sketching/july_2025/trait.dm b/sketching/july_2025/trait.dm new file mode 100644 index 0000000..ef4c0d5 --- /dev/null +++ b/sketching/july_2025/trait.dm @@ -0,0 +1,41 @@ +pub trait HasTruth + fn isTruthy() -> Boolean + + def fn isFalsy() -> Boolean = !self.truthy +end + +pub trait Functor[Self] + fn map(f: fn (t: T) -> U) -> Self +end + +pub trait Lift[Self] + static fn lift(t: T) -> Self +end + +pub trait Applicative[Self, U, V] : Functor[Self] + Lift[Self] where T is fn (u: U) -> V + fn apply(us: Self) -> Self +end + +pub trait Monad[Self] : Functor[Self] + Lift[Self] + fn flatMap(f: fn (t: T) -> Self) -> Self +end + +// Traits as higher-kinded types +// - Cannot be used as concrete types, casted, etc. +// - Cannot be constructed/instantiated +// - Imports are different: +// ``` +// use std::core::Option +// use std::trait::Monad[Option<*>] // bring in Monad for all Option<*> +// ``` +// - Once imported, fns are in scope +// - Can also be looked-up 'dictionary' style: +// ``` +// use std::trait::HasTruth[Option] +// +// fn main() +// let maybeTruthy: Option = someOtherApiCall() +// if HasTruth[maybeTruthy].isTruthy() then +// println "It's truthy." +// end +// ``` \ No newline at end of file