Pinned ping

you can't just put 50 blocked tickets on a kanban board and say you're agile*

*actually you can and that's in a nutshell why agile is shit

Pinned ping

t-shirt with a gay pride DNA helix and the text:

I Contribute To My Cousins' Evolutionary Success

Pinned ping

I try to end my days on a positive note which is why I always stay awake past midnight

in practice AI seems to be mainly very large companies who want to make a very large number of mediocre-to-bad decisions without paying people to make them

uh oh, I may have implemented enough of minor hobby programming thing that I'm less motivated to finish

re: code brag // 

( `<<<` is the function composition operator )

( that's probability 7/36 each for 1-5, 1/36 for 6 at the end )

( this would be much easier to read if the lines didn't wrap )

Show thread

code brag // 

import Distribution (Distribution, always, flatMap, uniformlyOver)

d6 :: Distribution Int
d6 = uniformlyOver [1,2,3,4,5,6]

data Rerollable a = Rerollable a | Final a

withoutRerolls :: forall a. Rerollable a -> Distribution a
withoutRerolls (Rerollable foo) = always foo
withoutRerolls (Final foo) = always foo

rerollTo :: forall a. Distribution a -> Rerollable a -> Distribution a
rerollTo dist (Rerollable _) = dist
rerollTo _ (Final foo) = always foo

roll :: forall a. Ord a => Distribution Int -> (Int -> Rerollable a) -> Distribution a
roll die toOutcome = flatMap ((rerollTo distWithoutRerolls) <<< toOutcome) die where
distWithoutRerolls = flatMap (withoutRerolls <<< toOutcome) die

> rerollSix = \n -> if n == 6 then Rerollable 6 else Final n
> roll d6 rerollSix
[( 0.194 -> 1 )
( 0.194 -> 2 )
( 0.194 -> 3 )
( 0.194 -> 4 )
( 0.194 -> 5 )
( 0.027 -> 6 )]

"koolasuchus" is an ancient proto-amphibian, but if you search duckduckgo for [ "koolasauchus" ] (with quotes) you get an almost random slice of its archived pages (different slices depending on which ddg node you hit, too)

* the city of Milan (wikipedia)
* company with "Terraform" in the name
* Chesapeake Public Schools parents' login
* list of boredom-busting activities like "go for a hike" "scrapbooking" "do your chores" "code something" from an anti-drug coalition
* arabic encyclopedia (?) results for "telecom companies in iraq"
* tiktok video from maybe sudan? someone stepping over a creek
* automated listserv notification about a Hadoop source code commit

"In summary, it is important to make people understand that groups can be identified with one-object groupoids. But next it is important to make clear that not everything that can be identified should be, for instance concerning the crucial difference between the category in which G lives and the 2-category in which BG lives."

I appreciate the way you think but I'm pretty sure if you forced random people to learn subtle semantic distinctions about category theory they would throw you out of windows a lot

re: re: getting less confused about functors // 

@octopus ah, one of them is the 'global failure' monad. it's the same as the usual, but if any of the 'intermediate' lists are empty, the entire output is empty

so under the usual monad, [1, 0, 3] >>= (\n -> [1..n])
evaluates to [1, 1, 2, 3]

but under the global failure monad it's just empty

re: monoid in the category of endofunctors but it's 3am // 

or maybe it's supposed to be

C5 objects:
C3 (the whole category, as 1 object)

C5 morphisms:
identity (C3 --> C3)
Array (C3 --> C3)
Array βŠ— Array (C3 --> C3)
Array βŠ— Array βŠ— Array (C3 --> C3)

this makes more sense, but nLab is talking about a two-level category (with objects, morphisms, and 2-morphisms = morphisms between the first level of morphisms)

Show thread

monoid in the category of endofunctors but it's 3am // 

an _endofunctor_ is a functor from a category and to itself

<Array> would be an endofunctor if applied to a category that already had arrays of everything, say, C3:

C3 objects (infinite):
Array (String)
Array (Array (String))
Array (Array (Array (String)))

C3 morphisms:

so, a "monoid in the category of endofunctors" would have 1 object (an endofunctor), and possibly many morphisms? say, C4:

C4 objects:

C4 morphisms:
identity (Array --> Array)
morphy (Array --> Array)
morphy βŠ— morphy (Array --> Array)
morphy βŠ— morphy βŠ— morphy (Array --> Array)

again the start/end (and therefore the actual element) of any monoid is kinda irrelevant

I think I'm missing a step here, in that a monad seems to be required to have a exactly one root non-identity morphism (here called "morphy") that composes with itself to form all the others

also, 3am

Show thread

re: re: getting less confused about functors // 

the morphism String.length might be realized as a function that takes an individual string and returns a particular number

but as defined, C1 doesn't know or care about any of that. the "implementation" is opaque to it β€” it doesn't even know that actual strings exist, just the abstract type String

and our Array functor doesn't have the ability to turn a particular string into any kind of array

but it does turn particular morphisms between Strings and Integers into morphisms between Array (String) and Array (Integer)

so, if
String.length "apple" = 5

Array.String.length ["apple", "banana"] = [5, 6]

could Array.String.length do something else? In this case, I think so, but if we had other morphisms like plus2 (Integer --> Integer) in C1, Array(plus2 βŠ— String.length) must be the same as Array.plus2 βŠ— Array.String.length; so it can't be too weird.

(the image of String.Identity *must* still be an identity element tho)

Show thread

re: getting less confused about functors // 

A _functor_ is like a structure-preserving function [f(a + b) = f(a) βŠ• f(b)], but instead of mapping elements of one thing to elements of a another thing, it maps from one category to another category

categories have two things (objects and morphisms between the objects) so a functor needs to deal with both of them

let's have category C1 with two objects
* String
* Integer
(not included: any particular number or string, only the "types")

and morphisms
* String.identity (String --> String)
* Integer.identity (Integer --> Integer)
* String.length (String --> Integer)

to be concrete, our functor will be Array, from C1 to C2

we map objects
String --> Array (String)
Integer --> Array (Integer)

and also morphisms
String.identity --> Array.String.identity (Array (String) --> Array (String))
String.length --> Array.String.length (Array (String) --> Array (Integer))

Show thread

re: getting less confused about monoids // 

Suppose monoid M* has countably many morphisms:
M1: Thingy --> Thingy
M2: Thingy --> Thingy
M3: Thingy --> Thingy
ad infinitum

then (M1 βŠ— M2) is… some other numbered morphism! Different monoids could do their morphisms differently here -- one might have M1 βŠ— M2 = M3, another might have M1 βŠ— M2 = M37.4432

suppose this one has composition like so

M1 βŠ— M1 = M2
M1 βŠ— M2 = M3
M1 βŠ— M3 = M4
M1 βŠ— M4 = M5

M2 βŠ— M1 = M3
M2 βŠ— M2 = M4
M2 βŠ— M3 = M5


M6 βŠ— M13 = M19
M10 βŠ— M10 = M20

…so, in this case, we might as well drop the M's and call our morphisms 1, 2, 3, &c

and call our composition operation something more common, like "addition"

the fact that all of our "numbers" are morphisms from Thingy to Thingy is only relevant to composition in that M1 βŠ— M2 requires M1 to start where M2 ends, which will always be satisfied in a monoid since there's only one object to start and end from

and that's how "the integers with addition" is a monoid.

Show thread

re: getting less confused about categories // 

a category is the objects + a bunch of morphisms between the objects *and* some structural guarantees, like
* every object Foo has its own (at least 1) personal identity morphism, Foo --> Foo
* if there's a morphism F from A to B, and a morphism G from B to C, then there's also a morphism from A to C that's F and G composed, "G βŠ— F" [think: g(f(x))]
* iow every category has a binary operation (composition) that takes two compatible morphisms and yields a third morphisms (and this binary operation is associative & has identities

A _monoid_ is a category with only one object. (Let's call it Thingy.) Therefore all of its morphisms start at Thingy, and also end at Thingy. (It only *needs* to have one morphism to satisfy the definition of category, but it can have more.) That means any pair of morphisms can be composed.

Suppose monoid M* has countably many morphisms:
M1: Thingy --> Thingy
M2: Thingy --> Thingy
M3: Thingy --> Thingy
ad infinitum

then (M1 βŠ— M2) is…

Show thread

getting less confused about categories // 

I think my original problem was thinking that "morphism" = "function". a function *is* a morphism but they're not synonyms exactly? idk what kind of morphism that *isn't* a function would be useful, but the point of morphisms is (maybe) that we can abstract away all the functiony bits.

morphism = a function's type signature?

backing up a bit, in a category, our "objects" might be things like Integer, String, Array (Integer), Array (Array (Integer)) [not sure if "Array (foo), for all foo in X" is okay at this level]

morphisms are directed edges with those objects as vertices: String --> Integer, Array (String) --> Array (Integer), Integer --> Integer

morphisms are not unique; you can have more than one morphism with the same start & end objects. "count the letters" and "count the capital letters" are two different functions & different morphisms from String --> Counting Numbers

a category is the objects + a bunch of morphisms between the objects

"a category is a monad in the 2-category of spans of sets"

making the definition of "category" dependent on the definition of "2-category" is one hell of a power move

(this article doesn't actually do that, it gives two good definitions w/ explanations, quoted text is from a list of technically equivalent definitions)

Show thread

Something I think a lot about: in aviation, if you're landing through fog (or whatever), the standard practice is to pick ahead of time a hard limit for the altitude at which you'll do a go-around. If you don't see the runway by the time that altitude is reached, you abort the landing attempt -- no questions.

Because otherwise folks tend to keep going "I'll just give it another few seconds..." until they're way too low for safety.

This type of protocol is very, very generalizable to everyday life, and can make decision-making a lot easier.

tshirt that reads, on the front


and on the back


re: octopus is typing // 

the problem interaction in T9A is Poison Attacks (on to-hit roll of 6, get 1 hit that automatically wounds) and Battle Focus (on to-hit roll of 6, get +1 hit)

Battle Focus + Poison Attacks + roll a 6 = 1 normal hit + 1 hit that autowounds

I *think* Daemon Legion and Undying Dynasties are the only armies that can get both traits onto the same model β€” Goblins have a monster w/ a similar interaction with Battle Focus, but I don't think they have a way to get Battle Focus onto it

and a few abilities like "if >= N attacks with property X hit, do Y" (where X could be on models that attack at different times in the combat round) which means I'm going to have to track (hits Γ— wounds) instead of just the most recent step

and again, the only abilities like that with N > 1 are in Daemon Legion

Show thread

re: octopus is typing // 

hanging over all of this is that I'm gonna need to implement re-rolls, too

so I guess every function is going to need to map to a distribution…?

like if you reroll 1s, then mapping a die roll has to be

6: 100% hit
5: 100% hit
4: 100% hit
3: 0% hit
2: 0% hit
1: 50% hit

ultimately flattening out to 7/12 hit, 5/12 miss

but I want my (roll β€”> outcome) to not need to know, say, how many faces were on the die

so I'll need an inner one that sometimes returns "reroll" & and outer one that actually does the rerolls

Show thread

octopus is typing // 

getting myself turned in circles w/ types, stepping away for a bit

I have a probability distribution type, Distribution <foo> (ie a die is Distribution Int)

I'm doing probability calculations for The 9th Age (community fork of old warhammer) combat.

the basic structure is:
* roll to hit
* for each hit, roll to wound
* for each wound, roll to save

so p(damage) = p(hit) * p(wound) * [1 - p(save)] which is pretty simple

except sometimes one attack can generate more than one hit, including hits of different strength, and some hits turn into a variable number of wounds

d6 :: Distribution Int
rollToHit :: (roll :: Int) --> Array Hit // eg 1-3 miss / empty array, 4-5 singleton hit, 6 two hits)
(map rollToHits d6) :: Distribution (Array Hit) // eg 50% [ ], 33% [Hit], 17% [Hit, Hit]

getRollToWound :: Hit --> (roll :: Int --> Distribution (Array Wound))
// ie strength 4 hit --> (roll 3+ --> 1d3 wounds)

mapping each array of hits into a flattened distribution of wounds & flattening that…

Show older

cybrespace: the social hub of the information superhighway jack in to the mastodon fediverse today and surf the dataflow through our cybrepunk, slightly glitchy web portal support us on patreon or liberapay!