Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • 02:10
    SethTisue edited #1511
  • 02:10
    SethTisue edited #1512
  • 02:09
    SethTisue labeled #1512
  • 02:09
    SethTisue labeled #1511
  • 02:09
    SethTisue assigned #1512
  • 02:09
    SethTisue opened #1512
  • 02:08
    SethTisue opened #1511
  • 00:23
    SethTisue commented #9815
  • 00:23
    SethTisue review_requested #9816
  • 00:22
    SethTisue edited #9816
  • 00:21
    SethTisue edited #9816
  • 00:21
    SethTisue labeled #9816
  • 00:21
    scala-jenkins milestoned #9816
  • 00:21
    SethTisue opened #9816
  • Nov 30 16:54
    som-snytt commented #9814
  • Nov 30 15:27
    eed3si9n commented #1510
  • Nov 30 15:26
    SethTisue commented #1510
  • Nov 30 15:26

    SethTisue on 2.13.x

    2.13: sbt 1.6.0-RC1 (was 1.6.0-… (compare)

  • Nov 30 15:25
    SethTisue closed #1510
  • Nov 30 15:13
    SethTisue commented #10129
RoelofWobben
@RoelofWobben
Hello, I have these two filters :
def filterOnNumberFilms(numberOfFilms : Int): Seq[String] = directors.filter(_.films.length > numberOfFilms ).map(director => director.lastName)

def bornBefore(year: Int) : Seq[String] = directors.filter(_.yearOfBirth < year).map(director => director.lastName)
Is there a way I can combine the two functions into one filter so I can filter on both
I can do .filter(….).filter(….)
but there must be a better way
Rob Norris
@tpolecat
You can define functions for each filter, of type Director => Boolean, then say .filter(d => f(d) && g(d)) or you can get more clever and define combinators for functions of that type and say .filter(and(f, g)) … there's a lot to explore. Note also that you can conjoin with both && and || and either might make sense.
Rob Norris
@tpolecat
In FP world we define a kind of addition/multiplication over functions and use that very general mechanism to combine them. It's a good observation you made and it leads to a lot of beautiful stuff.
RoelofWobben
@RoelofWobben
@tpolecat thanks :
def filterBoth(numberOfFilms : Int, year : Int):Seq[String] = bornBefore(year).filter(filterOnNumberFilms(numberOfFilms).contains)
yep, I know , Before I came here , I learned haskell and learned a lot about re-using functions or as they called it function composition if im right
Dominic Egger
@GrafBlutwurst
in FP scala a lot of the inspiration comes from haskell, i'm sure you'll see a lot of thigs you'll be familiar with
RoelofWobben
@RoelofWobben
yep, monads, functors , applicative , recursion, map, foldmap are a few
the first three are explained in the cats book
the syntax is different and that is the most difficult to pick up
@GrafBlutwurst
RoelofWobben
@RoelofWobben
time to sleep here , see you all tomorrow
Jason Pickens
@steinybot

I’m having some problems with path dependent types. Not sure if what I am trying to do makes sense. Anyway here is an example:

sealed trait Foo {
  type F
}

object Bar extends Foo {
  type F = Array[Byte]
}

trait Baz[B] {
  def b(b: B): String
}

object Baz {
  implicit val bazByteArray: Baz[Array[Byte]] = (b: Array[Byte]) => new String(b)
}

def f(a: Foo): Baz[a.F] = {
  val baz = a match {
    case bar@Bar => g(bar)
  }
  baz
} // Expression of type Baz[(a.type with Bar.type)#F] doesn't conform to Baz[a.F]

def g(a: Foo)(implicit baz: Baz[a.F]): Baz[a.F] = {
  baz
}

val x1: Bar.type = Bar
val y1: Baz[x1.F] = f(x1)

val x2: Foo = Bar
val y2: Baz[x2.F] = f(x2) // Expression of type Baz[Foo#F] doesn't conform to expected type Baz[x2.F]

What I don’t get is why g compiles but f doesn’t. Are the types not the same?

zetashift
@zetashift
Just a question out of curiosity, making a function a first class value you need to add an apply method(function?), why is it named apply?
Mathieu Prevel
@mprevel
object Test {
  def apply() = doSomething()
}
can be called Test()
this is a special case
Ichoran
@Ichoran
Ugh, this expression stuff is so clunky in this FP example.
There are perfectly reasonable OO ways to make the whole thing tidy, e.g.
trait Expr { def eval: Either[String, Double] }
sealed trait BinOp extends Expr {
  def a: Expr
  def b: Expr
  def op: (Double, Double) => Either[String, Double]

  protected def safe(f: (Double, Double) => Double): (Double, Double) => Either[String, Double] = 
    (xa, xb) => Right(f(xa, xb))

  def eval = a match {
    case Left(s) => Left(s)
    case Right(xa) => b match {
      case Left(s) => Left(s)
      case Right(xb) => op(xa, xb)
  }
}
final case class Add(a: Expr, b: Expr) extends BinOp { val op = safe(_ + _) }
final case class Sub(a: Expr, b: Expr) extends BinOp { val op = safe(_ - _) }
final case class Mul(a: Expr, b: Expr) extends BinOp { val op = safe(_ * _) }
final case class Div(a: Expr, b: Expr) extends BinOp {
  val op = (xa, xb) => if (xb == 0) Left("Division by 0") else Right(xa / xb)
}
Seth Tisue
@SethTisue
@zetashift because that’s what you’re doing, applying the function. it isn’t the only possible word that could have been chosen, for example JavaScript has apply but it also has call, Lisp has funcall, and so forth. Java also calls it apply
Fabio Labella
@SystemFw
the two solutions aren't equivalent with respect to extensibility @Ichoran . Expression problem and that
ime the OO one is the side of it you want less often
(final tagless can solve both sides, but that's a separate discussion)
Ichoran
@Ichoran
I don't know, I've written half a dozen expression evaluators and never once wanted to make the expressions extensible outside of the code that defines the operations in a way that isn't trivially handled by inheritance.
Fabio Labella
@SystemFw
you never wish to add a pretty printer and an evaluator?
adding ops is fairly common
adding nodes, less so
Ichoran
@Ichoran
Not outside of the evaluator, no.
I can of course envision cases where it's helpful, but I haven't run into them.
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