Sign in

Chris Penner

@chrispenner.ca
545 followers 608 following 263 posts

FP and Programming languages nerd Building the Unison Language & Unison Share 📍Victoria BC 🇨🇦 chrispenner.ca

PostsRepliesMedia
Chris Penner @chrispenner.ca · 04/08/2026
No other language lets me write straight-line code like this. The `prompt` line saves saves the current continuation in a database, then sends a prompt to the user's browser to select a slot. When selected, `prompt` returns the in-memory @unison-lang.org object which corresponds to the chosen slot.
timeslotOptions : [calendly.TimeSlot]
timeslotOptions = calendly.listEventTimeslots calendlyToken startTime endTime
form = timeslotOptions
        |> timeSlotsForm
          (ts ->
            ( eventName ts
            , calendly.TimeSlot.startTime ts
            , duration ts
            ))
chosenSlot : calendly.TimeSlot
chosenSlot = prompt timeslotsForm
170
Chris Penner @chrispenner.ca · 02/01/2026
Learning more #OpenSCAD in order to bring a #kumiko inspired table-lamp to life :)
160
Chris Penner @chrispenner.ca · 08/10/2025
P.s. try clicking the HAL9000 in the header;
030
Chris Penner @chrispenner.ca · 08/09/2025
We all know AI is unreliable, but what's the worst case you've seen? #zig This one made me exhale sharply through my nose today:
Zig doesn't have a built-in "defer on error" construct, but there are several patterns you can use to achieve similar functionality:
Method 1: Using errdefer (Zig's error-specific defer)
Actually, Zig does have exactly what you're looking for! It's called errdefer:
271
Chris Penner @chrispenner.ca · 06/08/2025
I do this sort of thing a lot, in #Haskell I love the tuple Monoid instance; pretty short, and only does a single list traversal.
230
Chris Penner @chrispenner.ca · 25/06/2025
Cool trick for finding bottlenecks in your concurrent systems; sometimes you can just literally print where you're currently blocked.
-- Hack for finding blocking points in your complex concurrent systems, 
-- you can literally just print where in the system you're blocked!

readQ :: String -> STM.TBMQueue a -> STM.STM (Maybe a)
readQ qName q = do
      STM.readTBMQueue q <|> do
        traceM $ "Blocked Reading from " <> qName
        retry
writeQ :: Text -> STM.TBMQueue a -> a -> STM.STM ()
writeQ qName q val = do
      STM.writeTBMQueue q val <|> do
        traceM $ "Blocked Writing to " <> qName
        retry
1121
Chris Penner @chrispenner.ca · 18/03/2025
Remove whimsy per terminal emoji rendering incongruence 😢
010
Chris Penner @chrispenner.ca · 19/02/2025
I wish I could use Waze, it's great, but the state of Anti-trust law in the U.S. is pitiful and Google bought it up.
Snippet from the Waze wikipedia page showing that it was purposed by Google and not challenged by anti-trust law.
020
Chris Penner @chrispenner.ca · 29/12/2024
I'm not quite sure what you're asking, but maybe this answers your question. Here's one way. Note that if you have more complex patterns you can delimit the scope of the wildcards like this: `pattern "%{name}-v%{num}.txt"` But the {} are optional if your wildcards have non-alphanumeric borders
echo 'myfile-v100.txt' | focus 'pattern "%name-v%num.txt" | "%name-v%{%num + 1}.txt"'
> myfile-v101.txt
100
Chris Penner @chrispenner.ca · 28/12/2024
I'm loving working on this little side project; I've got enough functionality to start using it in my daily dev life. E.g. now that I've got bindings, shell cmd support and pattern strings I can do nifty stuff like this little 'focus' script for renaming files.
# Rename every file from name.ext to name-old.ext
#
# `-> orig` binds the input string into the 'orig' var
# `pattern "%name.%ext"` does a pattern match on the string and binds the name and extension to vars
# `#{mv "%orig" "%name-old.%ext"}` calls out to the shell to move the file.
ls | focus '%. -> orig | pattern "%name.%ext" | #{mv "%orig" "%name-old.%ext"}'
180
Chris Penner @chrispenner.ca · 11/12/2024
New monad just dropped; `strict` behaves like `evaluate`, but you can run it purely. Anything you've called `strict` on will be evaluated when you force the result of `runStrictly` to whnf. Don't ask why I needed it... or why it has MonadFix... 😅
newtype Strictly a = Strictly (State () a)
  deriving newtype (Functor, Applicative, Monad, MonadFix)

strict :: a -> Strictly a
strict a = Strictly $ state \s -> (a, a `seq` s)

runStrictly :: Strictly a -> a
runStrictly (Strictly m) =
  let (a, s) = runState m ()
   in s `seq` a
050
Chris Penner @chrispenner.ca · 01/12/2024
Here’s my iPhone; the same thing happens with photos, most apps ask for full permissions when iOS offers options that are much more consumer friendly.
100