Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • 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
  • Dec 15 2021 03:07
    SethTisue edited #1312
  • Dec 15 2021 03:05
    SethTisue edited #1312
  • Dec 15 2021 03:05
    SethTisue edited #1312
  • Dec 15 2021 03:05
    SethTisue edited #1312
  • Dec 15 2021 02:58
    SethTisue edited #1312
  • Dec 15 2021 02:58
    SethTisue synchronize #1312
Ichoran
@Ichoran
Normally, I do it so that end-users won't have to bother thinking about what makes for a correct expression or how to pretty-print things; that's the point of me writing it at all.
Hopefully the FP example eventually gets to the point where it is helpful instead of just awkward?
Fabio Labella
@SystemFw

Normally, I do it so that end-users won't have to bother thinking about what makes for a correct expression or how to pretty-print things; that's the point of me writing it at all.

I don't understand this

as in , can't parse it
Ichoran
@Ichoran
So, I generally write expression trees like this when I want to offer a DSL as part of the API. The reason I do this is so I can think through the nonobvious stuff like what operations are valid and handle all the corner cases for the consumer of the DSL.
Abdhesh Kumar
@abdheshkumar
Just use flatMap on Future[Option[Double]]
Ichoran
@Ichoran
Extensibility implies that they get access to all the corners upon which they can poke themselves.
Avremel Kaminetzky
@avremel
@abdheshkumar thanks,
Ichoran
@Ichoran
Does that make more sense, @SystemFw ?
Fabio Labella
@SystemFw
well, if you're making a DSL, being able to interpret it seems reasonable
but the thing is
if you never need to extend it in any direction
the two approaches are exactly equivalent
except with the OO one the code logic is more scattered
rather than in one place like pattern matching
Abdhesh Kumar
@abdheshkumar
val r: Future[Option[Double]] = ???
r.flatMap{
case Some(v)=> Future.successful(v)
case None=> Future.failed(new Exception)}
Ichoran
@Ichoran
The pattern matching has a ton of repetition.
Fabio Labella
@SystemFw
where?
Ichoran
@Ichoran
Well, I guess I haven't seen what the gold-standard answer is supposed to be.
Fabio Labella
@SystemFw
I think the repetition there is mostly due to not being able to work with Either idiomatically because the appropriate combinators haven't been introduced yet
so a lot of matching on Left and Right
Ichoran
@Ichoran
Even then it's more machinery to get back to the same cleanliness of specifying operations.
Fabio Labella
@SystemFw
transforming things through pattern matching (complex trees) can indeed be tedious (that's where recursion schemes come into play), but I think that when you reach that point, the OO approach is hopeless anyway
@Ichoran I guess it depends on what you mean by cleanliness. For me being able to see all the logic for a given interpreter in one place is cleaner than it being scattered
Ichoran
@Ichoran
Yeah, OO is not well-suited to expression-simplification because it has very local perspective.
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]