Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • Sep 14 18:08
    @SethTisue banned @discjock:matrix.org
  • Sep 12 20:37
    @SethTisue banned @manuelzamoratetherbtcusa:matrix.org
  • Sep 06 14:29
    @SethTisue banned @white_hat_hacker:minds.com
  • Sep 06 14:29
    @SethTisue banned @alexchole:matrix.org
  • Aug 31 17:03
    @SethTisue banned @andersonwatts7:matrix.org
  • Jul 19 20:37
    @SethTisue banned @tonyobanon
  • Jan 02 23:58
    @SethTisue banned @fakubishes:nerdsin.space
  • Dec 15 2021 05:01
    som-snytt commented #12516
  • Dec 15 2021 04:38
    SethTisue edited #1312
  • Dec 15 2021 04:38
    SethTisue opened #2273
  • Dec 15 2021 04:31
    jackkoenig opened #12516
  • Dec 15 2021 04:29
    SethTisue edited #1312
  • Dec 15 2021 04:28
    SethTisue edited #1312
  • Dec 15 2021 04:27
    SethTisue labeled #9831
  • Dec 15 2021 04:27
    scala-jenkins milestoned #9831
  • Dec 15 2021 04:27
    SethTisue labeled #9831
  • Dec 15 2021 04:27
    SethTisue opened #9831
  • Dec 15 2021 03:35
    som-snytt commented #11339
  • Dec 15 2021 03:27
    som-snytt labeled #12494
  • Dec 15 2021 03:07
    SethTisue edited #1312
Ichoran
@Ichoran
I find it's easier to know "everything about Add" in one place, but I guess tastes may differ there.
Fabio Labella
@SystemFw
sure, and again they extend in different directions
if you want to add Mult, pattern matching breaks everywhere
if you want to add prettyPrint, overriding breaks everywhere
final tagless handles both :)
Ichoran
@Ichoran
Indeed. I find myself doing the former more than the latter, usually.
Fabio Labella
@SystemFw
right, I'm the opposite :joy:
but it makes sense
if you want to pick only one direction, it makes sense to pick the one you are exposed to more often
so in those circumstances I'd do dynamic dispatch as well
Ichoran
@Ichoran
Indeed.
In the case of an API like this, I generally find that there are very few sensible things to do with trees, but that I can supply a lot of handy operations as they come up, which means I add Mult way more.
But the more serious you get about tree-manipulation, I guess, the more that shifts the other way.
Fabio Labella
@SystemFw
yeah. Also I'm mostly using this kind of thing to build business level abstractions (like the Random thing I PRd to you), and using final tagless, which means I don't have to pick. The remaining use cases I have are (recreational ) compilers, for which the balance definitely shifts to pattern matching style
Ichoran
@Ichoran
I need to read a really clean description + use case for final tagless someday.
Fabio Labella
@SystemFw
I have a few scattered here and there, ping me if you ever get the time/will
Ichoran
@Ichoran
I haven't quite grokked why people like it so much--for instance, why it actually solves the "have to pick" problem.
Fabio Labella
@SystemFw
you can add new ops or new nodes without changing anything, while keeping type safety (if all ops aren't handled, things won't compile)
trait Add[A] {
  def num(i: Int): A
  def plus(l: A, r: A): A
}

def foo[A](implicit alg: Add[A]): A = alg.plus(alg.num(1), alg.num(2))
this is the basic form
interpreters are in the form of Add[Int] (which evals), or Add[String] (which pretty prints)
adding new ops like this doesn't require you to change any code
new ops would be a new Mult[A]
which also doesn't require you to change any code
calling code would be bar[A: Add: Mult]
Fabio Labella
@SystemFw
when you instantiate it at Int, if you don't have both instances things won't compile
Ichoran
@Ichoran
So you have to change all the call sites instead of all the class definitions and/or pattern matches?
Fabio Labella
@SystemFw
(there are a few differences among languages: here I'm passing things implicitly, so two interpreters with the same result type should be newtyped to keep coherence, you could also pass them explicitly)
@Ichoran not all the call sites
only the call sites that need the new op
which isn't "changing the call sites"
if you need the op, you need to call it, right?
Ichoran
@Ichoran
I guess that makes some sense.
Fabio Labella
@SystemFw
the shape people normally rave about have an F[_] type parameter
which allows you to encode effects
which compose seamlessly since typeclass constraints already compose
and can have multiple interpretations (e.g. test, prod)
Ichoran
@Ichoran
But it penalizes you pretty heavily for deeply nested code, doesn't it? Because if you need Mult, you have to adorn the entire call stack with it.
Fabio Labella
@SystemFw
isn't that the case with every constraint ever?
Ichoran
@Ichoran
No, because it's smuggled in via the class definition in an OO setting.
Fabio Labella
@SystemFw
right, I get what you mean, but that's because that one isn't a constraint
Ichoran
@Ichoran
Right. You're making people state their constraints instead of just using whatever is available, which seems like strictly more work. Safer and more minimal, but sometimes that's not very important.
Fabio Labella
@SystemFw
note that your approach also assumes you control the code that defines the language
i.e. if that's in a library, you're kinda screwed
Ichoran
@Ichoran
If it's a closed-source library, yeah.
Fabio Labella
@SystemFw
you can't make something extend an interface retroactively
Ichoran
@Ichoran
I pretty much decide I'm screwed regardless in that case, though :)
Fabio Labella
@SystemFw
even an open source one
Ichoran
@Ichoran
Well, you can always bolt on a typeclass.
Fabio Labella
@SystemFw
why should my DB library extend your custom interface that you use in user code?