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
Fabio Labella
@SystemFw

@mdedetrich agree to disagree :)

The benefit to complexity ratio of final tagless is excellent imho. But to each their own, no big deal

Ghost
@ghost~5c2a2354d73408ce4fb3431e
@SystemFw oh, don't get me wrong, I think "final tagless" in Scala is the best way to build FP apps... nothing comes close. I just don't think the name is a benefit to the cause. To me it's "just" using higher kinded types.
Fabio Labella
@SystemFw
@fommil actually I take it back, the hmap operation has the same shape I linked mapK. But yeah you have the kind problem
Ghost
@ghost~5c2a2354d73408ce4fb3431e
yeah, I lost a few hours on that ...
Fabio Labella
@SystemFw
@fommil well, when yesterday I told my colleague "write this BigQuery dsl in final tagless instead, and when [business thing] happens we will be able to easily extend", no higher kinds were involved, and the name brought value :)
Ghost
@ghost~5c2a2354d73408ce4fb3431e
@SystemFw pro tip Data.Composition is an excellent resource for implementing FFunctor instances....
heh, well so long as it works... then who cares about the name
Fabio Labella
@SystemFw
:+1: I'll have a look
Peter Aaser
@PeterAaser
Hai @fommil , how's haskell treating you?
And how's the kid?
Ghost
@ghost~54f837fe15522ed4b3dcd6a3
@ipergenitsa Yes, makes sense. But in which cases is it usually useful to use t.Typename?
Li Haoyi
@lihaoyi
i don't quite grok what it means to say encoding languages as their interpreters. e.g. Scalatags uses parametrization over F[_] to render to either Strings, js.Elements, or React VDom snippets. You compose a bunch of methods that return F[T], it returns a bigger F[T], and it looks just like any example of finally tagless that i've ever seen. Is Scalatags then finally tagless?
(it's parametrized over F[_] because it has different sets of tags, e.g. the tags from scalatags.Text.TypedTag[T] or scalatags.JsDom.TypedTag[T], and each tag is typed with the value returned when you render it)
Fabio Labella
@SystemFw
@lihaoyi give me a sec to approach it the right way
from your description scalatags is final tagless btw, it's just a matter of seeing what I mean
ok let's use the classical example of literals and addition
when asked to implement it, 98% percent of people will go for something like (with either pattern matching or OO dispatch, it doesn't matter)
sealed trait Op
case class Lit(i : Int) extends Op
case class Add(a: Op, b: Op) extends Op
programs are then datatypes of type Op
Add(Lit(1), Add(Lit(2), Lit(3))
Li Haoyi
@lihaoyi
yeah
Fabio Labella
@SystemFw
the interpreter then transforms that datatype
def eval: Op => Int = _ match {
   case Lit(i) => i
   case Add(a, b) => eval(a) + eval(b)
}
so there is a separation between interpreter and language
note some of the consequences:
  • you need to deal with recursion
  • you create an intermediate structure
  • hard to compose multiple language since datatypes aren't open (and if they were you'd lose exhaustiveness), so you need to rely on coproduct injections
  • and so on
Li Haoyi
@lihaoyi
yea
Fabio Labella
@SystemFw
With final tagless you say: "what do I need to interpret the Op language"
well
you need an interpreter for Lits, and an interpreter for Adds
and then you need a way of representing the result
let's say the result is A for now
you need
def lit(i: Int): A
def add(a: A, b: A): A
so, these are the interpreters for your language, how does the actual language look like?
well, we can say that the interpreter is the language (this is the same idea behind church encodings)
trait Op {
 def lit(i: Int): A
 def add(a: A, b: A): A
}
but what is A?
well that's the second idea: you just use a type param
trait Op[A] {
   def lit(i : Int): A
   def add(a: A, b: A): A
}
so you just define the language by packaging the interpreter
so what is an interpreter in final tagless?
given that interpreter and language are the same thing, an interpreter is just an instance of the language
Li Haoyi
@lihaoyi
trait Op[A] {
   def lit(i : Int): A
   def add(a: A, b: A): A
}
isn't that just the visitor pattern
Fabio Labella
@SystemFw
no
the visitor pattern doesn't encode it as a type param
and has the same drawback as pattern matching
you can extend with new interpreters, but not with new ops
if you want an OO term, it's "object algebras"
Li Haoyi
@lihaoyi
why can't the visitor encode it as a type param, type param or not seems orthogonal to visitor pattern or not
Fabio Labella
@SystemFw
the paper is Extensibility for the masses
Li Haoyi
@lihaoyi
just like visitors can have normal params, why not type params
Fabio Labella
@SystemFw
not for the return type