Sign in

Barry

@chiroptical.dev
1.1K followers 274 following 1.5K posts

PhD Theoretical Chemistry. Haskell/Typescript full stack engineer at Mercury. Aspiring Gleam and Erlang programmer. Occasional content creator linktr.ee/chiroptical. Drumming and fencing enjoyer.

PostsRepliesMedia
Barry @chiroptical.dev · 18/08/2026
It does say this on the website.
The section of the docs which mentions Elm and Haskell. Also “More languages to come”
120
Barry @chiroptical.dev · 09/08/2026
The image because it didn’t embed, probably my fault.
The image associated with my “palm reading”.  It’s almost a perfect hourglass shape. Calls me “The Weathervane” for some reason
010
Barry @chiroptical.dev · 06/08/2026
This also goofs me up semi-frequently.
1> A = <<0:32>>.
<<0,0,0,0>>
2> <<B:32>> = A.
<<0,0,0,0>>
3> B.
0
100
Barry @chiroptical.dev · 11/07/2026
This is huge progress for me!
150
Barry @chiroptical.dev · 12/06/2026
Got it. Some cleaning up to do. Also being able to count this in 4/4 and 6/8. Practice with the metronome etc.
010
Barry @chiroptical.dev · 09/06/2026
I was annoyed with all the metronome apps on the App Store so I just… made one. This is a M5Stack CoreS3.
Image of the UI which allows me to control the metronome
120
Barry @chiroptical.dev · 07/04/2026
Made some progress with ghost notes this week.
000
Barry @chiroptical.dev · 20/03/2026
Haven’t shared a drum video in a bit. This one is cool because you can see where I find the exercise and then really feel it.
100
Barry @chiroptical.dev · 11/02/2026
The initial setup is complete! Sonor AQX Jazz, Zildjian L80 cymbals, Yamaha hardware, RTOm black holes set. I’ll be able to play this with the kiddo asleep no issues!
Sonor AQX jazz drum set, Yamaha hardware, and Zildjian L80 cymbals in a lovely blue.
040
Barry @chiroptical.dev · 03/02/2026
Feeling like a powerful drumming warrior 😂
120
Barry @chiroptical.dev · 02/02/2026
This may be my best one so far.
A mediocre latte art
030
Barry @chiroptical.dev · 27/01/2026
Inspired by @whitep4nth3r.com here is part of my practice today. I’m about 3 weeks in, don’t judge me.
130
Barry @chiroptical.dev · 07/01/2026
TIL, this is legal #erlang compiles to `t() -> [f, o, o].`
-define(p, o, o]).
t() -> [f, ?p.
100
Barry @chiroptical.dev · 06/01/2026
Making progress on this foaming milk and pouring it into a cup thing
A poor latte art, but pretty close to the right texture
020
Barry @chiroptical.dev · 30/10/2025
Finished Section 2.2 of Mathematics in Lean. I'm skeptical that anything beyond this will make sense... This was labeled a hard exercise, but my brain has no idea why I would introduce `h` as a goal to solve this. I feel like I need more raw math skills which probably isn't surprising to some.
theorem mul_inv_cancel (a : G) : a * a⁻¹ = 1 := by
  have h : (a * a⁻¹)⁻¹ * (a * a⁻¹ * (a * a⁻¹)) = 1 := by
    rw [mul_assoc, ← mul_assoc a⁻¹ a, inv_mul_cancel, one_mul, inv_mul_cancel]
  rw [← h, ← mul_assoc, inv_mul_cancel, one_mul]
260
Barry @chiroptical.dev · 26/10/2025
Finished section 2.1 of Mathematics in #LeanLang.
example (a b : ℝ) : (a + b) * (a - b) = a ^ 2 - b ^ 2 := by
  rw [mul_sub, add_mul, add_mul, <- pow_two, <- sub_sub, mul_comm, <- add_sub, sub_self, <- pow_two, add_zero]
130
Barry @chiroptical.dev · 26/09/2025
#gleamlang do we prefer builder style here or just `encrypt(BitArray, Option(BitArray))`? For some reason, I don't like `encrypt(x, option.None)` but also `new(x) |> encrypt()` feels tedious. `encrypt_with_associated_data(x, y)` feels long.
  let encrypted =
    new(<<"thing">>)
    |> associated_data(<<"thing">>)
    |> encrypt()

  let decrypted =
    new(encrypted)
    |> associated_data(<<"thing">>)
    |> decrypt()
100
Barry @chiroptical.dev · 21/09/2025
Design is my passion…
Magnetic tiles for children, isosceles triangles arranged in a circle, except there is a small gap where you couldn’t fit another one of the tiles.
030
Barry @chiroptical.dev · 17/09/2025
Post a movie you like with a terrible rotten tomatoes score.
Rotten tomatoes screen capture for Surf Ninjas. 23% tomato meter. 68% popcorn meter.
110
Barry @chiroptical.dev · 26/08/2025
Imagine I know nothing about cryptography. It shouldn't be hard. Does this look reasonable? (I'm planning on storing the key in the environment, my hosting provider can encrypt them which is why I thought base64 would be fine?). #erlang
-module(util_crypto).

-export([
    encrypt/1,
    decrypt/1
]).

%% Generated example key with base64:encode(crypto:strong_rand_bytes(16)).
-define(KEY, ~"13jNvhABaUhX8q0o0WHyPg==").

encrypt(Value) ->
    Iv = crypto:strong_rand_bytes(16),
    Encrypted = crypto:crypto_one_time(aes_128_ctr, base64:decode(?KEY), Iv, Value, true),
    <<Iv/binary, Encrypted/binary>>.

decrypt(<<Iv:16/binary, Value/binary>>) ->
    crypto:crypto_one_time(aes_128_ctr, base64:decode(?KEY), Iv, Value, false).
210
Barry @chiroptical.dev · 22/08/2025
The one I got (probably RedBubble?) adds a slight white border around the logo.
A shirt with the Erlang logo on it.
110
Barry @chiroptical.dev · 09/08/2025
Someone suggested this book to me. The preface speaks to me. Hopefully I learn something.
Picture of the book “A Philosophy of Software Design” by John Ousterhout
240
Barry @chiroptical.dev · 09/08/2025
I like this a lot better than my previous implementation. It is obvious in hindsight. #erlang
-spec decode_interact_contents(jsx:json_term() | {incomplete, jsx:decoder()}) ->
    {some, #interact_contents{}} | none.
decode_interact_contents(
    #{
        ~"channel_id" := #{~"id" := ChannelId},
        ~"user" := #{~"id" := UserId},
        ~"team" := #{~"id" := TeamId},
        ~"response_url" := ResponseUrl,
        ~"actions" := #{~"value" := SubmittedUrl}
    }
) ->
    {some, #interact_contents{
        channel_id = ChannelId,
        user_id = UserId,
        team_id = TeamId,
        response_url = ResponseUrl,
        submitted_url = SubmittedUrl
    }};
decode_interact_contents(_) ->
    none.
000
Barry @chiroptical.dev · 07/08/2025
Why do I need to add these dependencies to dialyzer? They are listed in my `deps` section of rebar.config? #erlang
{dialyzer, [
    {warnings, [unknown]},
    {plt_apps, top_level_deps},
    {plt_extra_apps, [uuid, elli, jsx, eunit, ssl]}
]}.
000
Barry @chiroptical.dev · 23/07/2025
Finally had time to get my index.html into #unisonlang and serve it locally. I haven't been super motivated to work on this project but making some progress!
Left: unison ucm console serving my HTML page
Right: a basic design for a new declarative.tv page with some mock data
140
Barry @chiroptical.dev · 14/06/2025
This is less text than the `switch` example but it is **so** boring. I want to see the supercharged Qi example.
(define-flow fizzbuzz-simple
             (>< (if match-fizz
                     (if match-buzz "fizzbuzz" "fizz")
                     (if match-buzz "buzz" ~v))))
(fizzbuzz-simple 3 5 15 31)
000
Barry @chiroptical.dev · 18/05/2025
I was supposed to read structs/modules first but I couldn't help but peak at contracts. This fails at run-time because 0 is not positive.
(define positive-number (and/c number? positive?))

(define/contract (add-positive-amounts x y)
  (-> positive-number positive-number positive-number)
  (+ x y))

(add-positive-amounts 0 0)
100
Barry @chiroptical.dev · 11/05/2025
Set up #racketlang with #helixeditor. Requires `raco pkg install racket-langserver` and `raco pkg install fmt`.
[language-server.racket-langserver]
command = "racket"
args = ["-l", "racket-langserver"]

[[language]]
name = "racket"
auto-format = true
formatter = { command = 'raco', args = ["fmt"] }
language-servers = [ "racket-langserver" ]
250
Barry @chiroptical.dev · 14/02/2025
A quick diagram of focus' services. The credential manager and developer log services typically run in their own #erlang node. The focus service runs in an erlang node displayed to your #Twitch stream. A connection to Twitch web socket displays chat, follows, and subscriptions.
A diagram showing how the focus services are connected. Running `twitch:msg(~"Hello").` will call the credential manager for an access token, call the Twitch API, and then get a message back from a web socket to display back to stream.
100
Barry @chiroptical.dev · 25/01/2025
Distributed #erlang anyone? Conceptually, focus can have an admin log which doesn't have to be visible on stream.
Two terminals running an erlang shell side by side. In the right, I run a gen_server which has a logger. On the left, I connect to the right and make an RPC to that logger. On the right, I see that log printed.
130
Barry @chiroptical.dev · 22/01/2025
We now have chat, follows, and subscriptions in Erlang.
A side by side of Twitch chat (left) and focus (right) displaying the contents of Twitch chat. Focus brings Twitch chat to the Erlang development shell.
010
Barry @chiroptical.dev · 17/01/2025
Card games are good for you!
Three board games: The Gang, Skull King, and Seas of Strife. The games are on my counter.
010
Barry @chiroptical.dev · 19/12/2024
Easy, but fun, lexer/parser for adventofcode.com/2024/day/19 advent of parsers in #erlang.
Definitions.

COLOR   = [wubrg]
NEWLINE = \n
COMMA   = ,
SPACE   = [\s]+

Rules.

{COLOR}   : {token, {color, TokenLoc, to_color(TokenChars)}}.
{NEWLINE} : {token, {newline, TokenLoc}}.
{COMMA}   : {token, {comma, TokenLoc}}.
{SPACE}   : skip_token.

Erlang code.

to_color("w") -> white;
to_color("u") -> blue;
to_color("b") -> black;
to_color("r") -> red;
to_color("g") -> green.Nonterminals colors patterns designs input.

Terminals color comma newline.

Rootsymbol input.

colors -> color        : [from('$1')].
colors -> color colors : [from('$1') | '$2'].

patterns -> colors newline        : ['$1'].
patterns -> colors comma patterns : ['$1' | '$3'].

designs -> colors newline         : ['$1'].
designs -> colors newline designs : ['$1' | '$3'].

input -> patterns newline designs : {'$1', '$3'}.

Erlang code.

from({color, _Loc, X}) -> X.
030
Barry @chiroptical.dev · 19/12/2024
Every year I generate one of these at work. At Mercury, every individual gets a callsign. It is a name and an emoji. I am :blueranger: (see {2, 2} in the image, 0 indexed). It is crazy to think where it started and where it is now.
A 32x30 image where each cell has a "callsign". A callsign is an essentially a name paired with an emoji given to individuals at my job. For example, my callsign is blueranger and my emoji is a picture of the blue ranger from power rangers.
020
Barry @chiroptical.dev · 10/12/2024
Advent of parsers day 9. I really wanted to do something more interesting here but I couldn't come up with a way to get the file index in there. One idea I had was to return the `Col` and then build a `Map Col Idx` and just lookup the file's idx later.
Nonterminals value disk_map file free_space.

Terminals number.

Rootsymbol disk_map.

value -> number : to_value('$1').

file -> value : to_file('$1').

free_space -> value : to_free_space('$1').

disk_map -> file                     : ['$1'].
disk_map -> file free_space disk_map : ['$1', '$2' | '$3'].

Erlang code.

to_value({number, _Col, Value}) ->
	Value.

to_file(X) ->
	{file, X}.

to_free_space(X) ->
	{free_space, X}.
110
Barry @chiroptical.dev · 07/12/2024
Feeling cute, might delete later. #erlang
build_magmas(TestValue, Threes) ->
    [
        fun(A, B) -> F(TestValue, A, B) end
     || F <- Threes
    ].
020
Barry @chiroptical.dev · 07/12/2024
Feeling better, updated lexer and parser and finished day 6 part 1 of #adventofcode. The parser now outputs a map with no intermediate list 🤩
Definitions.

DOT     = \.
OCTO    = #
CARROT  = [<>^v]
NEWLINE = \n

Rules.

{CARROT}  : {token, {guard, TokenLoc, to_atom(TokenChars)}}.
{OCTO}    : {token, {obstacle, TokenLoc}}.
{DOT}     : {token, {blank, TokenLoc}}. 
{NEWLINE} : skip_token.

Erlang code.

to_atom("<") ->
	west;
to_atom(">") ->
	east;
to_atom("^") ->
	north;
to_atom("v") ->
	south.Nonterminals map.

Terminals guard obstacle blank.

Rootsymbol map.

map -> guard        : to_map('$1').
map -> obstacle     : to_map('$1').
map -> blank        : to_map('$1').
map -> guard map    : insert(to_kv('$1'), '$2').
map -> obstacle map : insert(to_kv('$1'), '$2').
map -> blank map    : insert(to_kv('$1'), '$2').

Erlang code.

to_map({guard, Position, Direction}) ->
	#{Position => {guard, Direction}};
to_map({Atom, Position}) ->
	#{Position => Atom}.

to_kv({guard, Position, Direction}) ->
	{Position, {guard, Direction}};
to_kv({Atom, Position}) ->
	{Position, Atom}.

insert({K, V}, M) ->
	maps:put(K, V, M).
010
Barry @chiroptical.dev · 06/12/2024
Feeling sick so taking a break from #adventofcode. I'll try to keep up with at least the lexer/parsers for advent of parsers. The lexer gives us the positions for free. The guard is described by a cardinal direction. #erlang
Definitions.

DOT     = \.
OCTO    = #
CARROT  = [<>^v]
NEWLINE = \n

Rules.

{CARROT}  : {token, {guard, TokenLoc, to_atom(TokenChars)}}.
{OCTO}    : {token, {obstacle, TokenLoc}}.
{DOT}     : skip_token.
{NEWLINE} : skip_token.

Erlang code.

to_atom("<") ->
	west;
to_atom(">") ->
	east;
to_atom("^") ->
	south;
to_atom("v") ->
	north.Nonterminals map.

Terminals guard obstacle.

Rootsymbol map.

map -> guard : [from_guard('$1')].
map -> obstacle : [from_obstacle('$1')].
map -> guard map : [from_guard('$1')|'$2'].
map -> obstacle map : [from_obstacle('$1')|'$2'].

Erlang code.

from_guard({guard, {X, Y}, Direction}) ->
	{{X, Y}, Direction}.

from_obstacle({obstacle, {X, Y}}) ->
	{{X, Y}, obstacle}.
120
Barry @chiroptical.dev · 05/12/2024
Haven't had a chance to finish the algorithm,but the lexer and parser was easy for 2024 day 5 #adventofcode
Definitions.

NUMBER  = [0-9]+
PIPE    = \|
COMMA   = ,
NEWLINE = \n

Rules.

{NUMBER}  : {token, {number, TokenLoc, list_to_integer(TokenChars)}}.
{PIPE}    : {token, {pipe, TokenLoc}}.
{COMMA}   : {token, {comma, TokenLoc}}.
{NEWLINE} : {token, {newline, TokenLoc}}.

Erlang code.Nonterminals integer integer_and_loc instructions rules update updates.

Terminals number pipe comma newline.

Rootsymbol instructions.

integer -> number : value('$1').

integer_and_loc -> number : value_and_loc('$1'). 

instructions -> rules newline updates : {'$1', '$3'}.

rules -> integer pipe integer newline       : [{'$1', '$3'}].
rules -> integer pipe integer newline rules : [{'$1', '$3'} | '$5'].

update -> integer_and_loc comma        : ['$1'].
update -> integer_and_loc              : ['$1'].
update -> integer_and_loc comma update : ['$1' | '$3'].

updates -> update newline         : ['$1'].
updates -> update newline updates : ['$1' | '$3'].

Erlang code.

value({number, _Loc, Value}) -> 
	Value.

value_and_loc({number, {_Row, Col}, Value}) -> 
	{Value, Col}.
140
Barry @chiroptical.dev · 04/12/2024
Advent of parsers day 4 #erlang leex and yecc. The TokenLoc from leex gives us the row and column. The parser reshapes the token into a form ingestible by map:from_list/1.
Definitions.

XMAS        = [XMAS]
NEWLINE    = \n

Rules.

{XMAS}                : {token, {xmas, TokenLoc, TokenChars}}.
{NEWLINE}             : skip_token.

Erlang code.
Nonterminals chars.

Terminals xmas.

Rootsymbol chars.

chars -> xmas      : [reshape('$1')].
chars -> xmas chars : [reshape('$1')|'$2'].

Erlang code.

reshape({xmas, {Row, Col}, Xmas}) ->
	{{Row, Col}, Xmas}.
260
Barry @chiroptical.dev · 02/12/2024
Guess how much faster this is than a list based accumulator #erlang. I benchmarked it with a list of 10K and 100K elements with various N.
-spec drop_nth(pos_integer(), list()) -> list().
drop_nth(N, X) ->
    drop_nth_inner(N, X, queue:new()).

-spec drop_nth_inner(pos_integer(), list(), queue:queue()) -> list().
drop_nth_inner(1, [_Head | Tail], Acc) ->
    lists:append(queue:to_list(Acc), Tail);
drop_nth_inner(_N, [], Acc) ->
    queue:to_list(Acc);
drop_nth_inner(N, [Head | Tail], Acc) ->
    drop_nth_inner(N - 1, Tail, queue:in(Head, Acc)).
010
Barry @chiroptical.dev · 02/12/2024
Used some 'maybe' expressions to encode the rules. I figured part 2 would introduce more complicated rules but alas.
increasing_rule(X, Y) ->
    maybe
        ok ?= case X < Y of
            true -> ok;
            false -> error
            end,
        ok ?= case Y - X < 4 of
            true -> ok;
            false -> error
            end,
        true
    else
        error -> false
    end.
210
Barry @chiroptical.dev · 02/12/2024
Advent of parsers day 2! Very easy yecc description to get a list of reports.
Nonterminals level report reports.

Terminals int newline.

Rootsymbol reports.

level -> int : extract_level('$1').

report -> level         : ['$1'].
report -> level report  : ['$1'|'$2'].

reports -> report newline         : ['$1'].
reports -> report newline reports : ['$1'|'$3'].

Erlang code.

extract_level({_Token, _Line, Value}) -> Value.
180
Barry @chiroptical.dev · 16/11/2024
A super quick demo. No BE interaction yet but I'll work on that next.
000
Barry @chiroptical.dev · 15/11/2024
You down with OPP? #CodeBEAM
A slide that says ‘OpenTelemetryProcessPropogator.fetch_parent_ctx’
020
Barry @chiroptical.dev · 01/06/2024
@arachno.capital a photo for you
Little spider babies in their little spider web
010
Barry @chiroptical.dev · 26/05/2024
🎉
141
Barry @chiroptical.dev · 30/03/2024
My new summer obsession
A blue Suzuki GSX-8R
000
Barry @chiroptical.dev · 08/02/2024
Someone asked for a cozy picture of Andre 3000. Here he is just moments ago rolling around 😊
3212
Barry @chiroptical.dev · 07/02/2024
This is Andre 3000. He had to go to the ER recently and they missed the first IV hence two shaved arms. He is doing great now.
5310