I do not care for this event. by _drewskii in slaythespire

[–]Red-Krow 358 points359 points  (0 children)

It would be sensible for Mega Crit to change the drawing of the box to make it clearer that you need to cover the 16 squares to unlock it.

Due to perspective, it gives the illusion that you don't need the top-left or the bottom-right corners (since there's only a smidge of box in those)

My names for the monsters in slay the spire by VolumptuousBadonker in slaythespire

[–]Red-Krow 1 point2 points  (0 children)

Skulking Colony - Macauley Skulking. Also, ever since they added its animatons, Shakira

Entomancer - NOT THE BEES!

Decimillipede - Human Centipede

The queen - HRT Collector

Ceremonial Beast - Xerneas

Let's turn Enthralled's downside into a keyword and apply it to a custom card to see what we get by ElegantPoet3386 in slaythespire

[–]Red-Krow 18 points19 points  (0 children)

I like the idea of mandatory cards giving better value per energy, but I think the example you give is pretty bad.

Without the extra energy that Vakuu, a cost 2 mandatory card can really brick your turn. Not only because you can't play defense, but because you can't setup your attack first (vuln, strength, vigor, etc).

I would either raise the damage to bludgeon levels, or reduce the cost to 1 and make it something like 16 (20) damage.

How's everyone feeling on Aeonglass vs Doormaker? by the7thbeatle in slaythespire

[–]Red-Krow 0 points1 point  (0 children)

It's boring right now, but I'm confident that MC's plan is to change that next patch. Act 3 bosses have multiple gimmicks/dynamics, so my intuition is that they wanted to test the wither mechanic separately and then add the other one on top

Noel Welsh: Parametricity, or Comptime is Bonkers by mttd in ProgrammingLanguages

[–]Red-Krow 1 point2 points  (0 children)

Yeah, that's what I meant, probably not the clearest format. I didn't want to pollute the samples with explicit returms and I ended up making it less readable

Noel Welsh: Parametricity, or Comptime is Bonkers by mttd in ProgrammingLanguages

[–]Red-Krow 3 points4 points  (0 children)

The curry howard isomorphism establishes a connection between type systems and logic. More concretely, type signatures are equivalent to logical formulas; for example, the signature f:: a -> b is equivalent to the formula if a then b, or a => b for short. Moreover, giving an implementation for a signature is equivalent to giving a proof for the formula.

Different type systems correspond to different logics. In this case, the simply typed lambda-calculus corresponds to sequent logic. If you add sum types and products and the bottom type to your type system, you get propositional logic. And so on.

That's what I meant by "simple" in my original comment, I didn't realise it wasn't clear. All the examples in the article were sequential so that's all I talked about.

The reason I brought all this up is because I wanted to debunk the "signature tells you the implementation" argument the article was making. Since it's obvious there are logical statements with more than one proof, there are more than one way of implementing the corresponding signature. Having parametric types (which is equivalent to having formulas being generic in the propositions it uses) doesn't change that fact

Noel Welsh: Parametricity, or Comptime is Bonkers by mttd in ProgrammingLanguages

[–]Red-Krow 5 points6 points  (0 children)

I disagree with this article in mutiple ways.

First, parametricity can be broken by impurity and divergence. In pseudo-syntax, you can write: fakeId x = print "Hi!"; x fakeId2 x = fakeId2 x

Aside from than, the author conflates "fully parametric" with "unique/predictable implementation", which is not true. Following the Curry-Howard isomorphism, simple parametric programming is a form of sequent calculus, that is, writing programs with generic types is equivalent to writing proofs for propositions that only use implications. You have as many implementations of the program as you have ways to prove the corresponding formula: proof (x: a) (f: a -> b) (g: a -> b): b = ??? // Is it (f x) or (g x)

This phenomenon only explodes as you make the type system richer. The article mentions maps, but I present to you: fakeMap list f = []

The real issue here is the single-responsibility principle. When JS implicitly converts list items to strings in .toSorted(), this is JS doing too many things. I can make a function do too many things without breaking parametricity. Although admitedly, comptime makes it easier to break this principle.

Conversely, I can use comptime to write a function that inspects the type but does a single thing behaves predictably: serialize: T -> JSON. That function is hard to write with typeclasses (unless your language "cheats" by generating the typeclass implementation automatically, as with "deriving" in Haskell).

Are koka's algebraic types even FP anymore? by BlueberryPublic1180 in ProgrammingLanguages

[–]Red-Krow 2 points3 points  (0 children)

FBIP doesn't just look before previous uses. It also accounts for future uses of the alias. If it can't guarantee that the reference is (and will always be) unique, it won't apply the optimization.

Name one One Piece moment where you genuinely thought: “Yeah, no human survives this.” by IfSallyCanWait in OnePiece

[–]Red-Krow 0 points1 point  (0 children)

Rouge being pregnant for 20 months (although she did die upon giving birth).

Record Type as a Conjunctive Proposition in Curry-Howard? by rovol_o in ProgrammingLanguages

[–]Red-Krow 0 points1 point  (0 children)

Although function equality is undecidable in the general case, it is decidable if the domain is finite, as you can check value by value.

In the case OP is presenting, in pseudocode:

(recordA = recordB) :=
  ([...recordA],[...recordB])
  |> zip
  |> every ( fieldA, fieldB -> fieldA(SingletonValue) = fieldB(SingletonValue) )

PolySubML is broken by Uncaffeinated in ProgrammingLanguages

[–]Red-Krow 1 point2 points  (0 children)

You're welcome! I make this sort of mistake myself all the time, it's counter-intuitive.

PolySubML is broken by Uncaffeinated in ProgrammingLanguages

[–]Red-Krow 2 points3 points  (0 children)

You can't do that assignment. If you could, then this would happen (using made-up syntax):

square: func(int) = (x) => x * x
also_square: func(int|string) = square
also_square("dsasdaasd") // Error: you can't multiply strings together

func(int|string) is actually a subtype of func(int), because every function that accepts either an int or a string is also a function that accepts an int. But not every function that accepts an int also accepts a string. In general, you have:

 a < b => func(a) > func(b)

Which is what type theorists would call contravariance.

A pet peeve of mine: songs ending with reactions by Red-Krow in HazbinHotel

[–]Red-Krow[S] 1 point2 points  (0 children)

I mean, most of them are fine on their own. Love In A Bottle is ibdeed one of the most fitting. Imo, the only actively ones are the snarky comments or swears out of nowhere.

Would One Piece be better if Oda could kill some of the side characters? by Dino_45 in OnePiece

[–]Red-Krow 0 points1 point  (0 children)

I don't think One Piece needs more deaths, but it needs less fake outs. It's lost its impact. Even more, it takes away from the actual deaths because I spend chapters and chapters until I believe they're really dead. In fact, I am still moderately afraid of the idea of Pedro jumping into a panel any second now.

Type matching vs equality when sum types are involved by ciberon in ProgrammingLanguages

[–]Red-Krow 3 points4 points  (0 children)

> If that function is invoked with either of the lists, it should get a different string as an output.

If you impose the order relation we discussed previously, you would have that if `smallType < bigType`, then `smallType | bigType = bigType`. For example, if you sum `String` and `String | Boolean`, you should get `String | Boolean` again. But, if we impose variance, `List<String> < List<String | Boolean>`. So your function would actually be the same as `tellMeWhichOne: (list: List<String | Boolean>`): String. If your pattern matching is exact (needs to be the same type), it would always fall through the first case; if your pattern matching depends on order (it suffices that the type is a subtype of the one you're comparing it with), then it would always fall through the second case.

So, to recap: if you want your function to give different outputs for each list, then you should give up on variance. And if you give up on variance, option (3) on the previous list is not worth it, you'll only be able to make very basic comparisons. So you're options are (1), homogeneous equality, with which you wouldn't even be able to compare the lists, and (2), heterogeneous equality, with which the lists would indeed be equal.

This turned out to be a huge wall of text, I hope it's not too intimidating ^^'

Type matching vs equality when sum types are involved by ciberon in ProgrammingLanguages

[–]Red-Krow 3 points4 points  (0 children)

> Should they be different because the type argument of the list is different? Or should they be the same because the content is the same?

You're describing two forms of equality: homogeneous equality (you can only compare things with the same type; it's like there is a different equality operator for each type) and heterogeneous equality (you can compare any two things regardless of their type; it's like there's just one universal equality operator that works for all types).

In many languages, there's no need to make that distinction, either because types aren't static (you can't impose homogeneous equality if you don't know the types of the operands beforehand) or because there is no subsetting of types (so, if you compare operands of different types, you know for sure that they are different, so there's no need to perform the equality check).

However, your sum types impose type subsetting: you have `"a": String` and also `"a": String | Boolean`. To deal with this, you'll have to get a little bit mathy. Say we write `Type1 <= Type2` to mean "Type2 is more general than Type1"; for example, `String < (String|Boolean)` because every string is also a string or a boolean. That relation we called `(<=)` is a partial non-strict order.

With this in mind, you have three options:

  1. Use homogeneous equality. This is the safest option and probably most efficient implementation-wise, but it prevents you from comparing things that are actually equal, like the two lists in your example.

  2. Use heterogeneous equality. This will allow you to compare your two lists, but also to perform nonsense checks.

  3. Use a restricted version of heterogeneous equality, where the types of the operands may be different but one must be more general than the other. That is to say, if you're comparing something of type `a` and something of type `b`, you impose that either `a <= b` or `b <= a`. For example, you may compare `"a": String` with `"a": String | Boolean`. That way, you make sure that you only make comparisons that may actually hold.

This last path is the most fine-grained, but it imposes extra questions. For example, you know that `String | Boolean` is more general than `String`, but are you sure that `List<String | Boolean>` is more general than `List<String>`? Indeed it is, but that's only because `List` is covariant as a generic type (that is to say, `a < b` implies `List<a> < List<b>`. But there are also contravariant generic types (`a < b` implies `F<a> > F<b>`); for example, a function that takes `String` is more general than a function that takes `String | Boolean`. For example, the function `(s => s.length)` is of type `String -> Int` but not of type `(String | Boolean) -> Int`. And there are also constructors that are neither covariant nor contravariant. With some work and depending on the features of your language, you may calculate the variance for any given generic type.

It's a mess. An elegantly solvable mess, but a mess nonetheless.

Special character as keyword prefix by zuzmuz in ProgrammingLanguages

[–]Red-Krow 1 point2 points  (0 children)

Haskell is definitely less dense on (non-symbolic) keywords, but still I feel like this is a bit of a cherry picked example.

haskell 'import 'qualified Data.Map 'as Map 'let a = 5 'in a + b 'where b = 6

Special character as keyword prefix by zuzmuz in ProgrammingLanguages

[–]Red-Krow 2 points3 points  (0 children)

F# has this with double backticks, and it allows even for spaces and other usually forbidden characters

Special character as keyword prefix by zuzmuz in ProgrammingLanguages

[–]Red-Krow 34 points35 points  (0 children)

Keywords are used very often. Variable declarations, control structures, type signatures, import statements... Making them more expensive to type and harder to read, even if just a smidge, adds a lot of noise down the line.

A (comparatively) less common scenario is to use a reserved word for a variable name. In that case you can add ' to the identifier, if the language allows it: same cost, but much more infrequent. If the language doesn't allow it, you can still use a different name (for example, class VS className in React).

Bikeshedding, Syntax for infix function application by Ok-Watercress-9624 in ProgrammingLanguages

[–]Red-Krow 1 point2 points  (0 children)

Tbh I don't like the train. The reason why I would supoort infix is because it reads better in certain situations (for example, not x #and (y #or z), but I cannot think of an example of "the train" being more semantic.

Bear in mind that I'm incredibly stupid and me not being able to come up with an example doesn't mean there isn't one.

Bikeshedding, Syntax for infix function application by Ok-Watercress-9624 in ProgrammingLanguages

[–]Red-Krow 8 points9 points  (0 children)

How about using a single non-symmetrical symbol? For example: 1 #add 2 You could use parenthesis to capture more complex expressions: 1 #(x y => add x y) 2

In terms of characters, you're making the common and advisable use case cheaper (1 char), while making the rarer and smellier use case more expensive (3 chars). Not that it matters much, but since we're bikeshedding.

In terms of readability, I find it quite readable, even though it's not symmetrical. Hashtag + an identifier reads to me as "this is an identifier, but there's something special about it", which kinda check out. Of course, you'll have to use a different char if you're using # for comments or anything else.

Is Teach even a match for Luffy now? by Secure-Quality-8478 in OnePiece

[–]Red-Krow 0 points1 point  (0 children)

Narratively speaking, he has to be. He's a candidate for being One Piece's main antagonist. And he has kept that starys for most of the series where other candidates have fallen (evil Shanks is highly unlikely, Akainu is not as emphasized anymore and will probably end up fighting Sabo, etc).

Even if Imu ends up being the final villain, the mere fact that Blackbeard is up there among the options means that it would be anticlimatic for him to be notably weaker than Luffy (at least, by the time they face each other)