I'm playing with pattern matching, but I have some difficult to understand what's wrong with this piece of code:
class Expr {
case class Number(v : Int) extends Expr
case class Sum(a : Expr, b : Expr) extends Expr
def show(e: Expr): String = {
e match {
case Number(a) => a.toString()
case Sum(a, b) => "(" + show(a) + "+" + show(b) + ")"
}
}
override def toString() = show(this)
}
class Number(v : Int) extends Expr
class Sum(a : Expr, b : Expr) extends Expr
object Number {
def apply(v : Int) = new Number(v)
}
object Sum extends Expr {
def apply(a : Expr, b : Expr) = new Sum(a, b)
}
object ExpressionProblem {
def main(args: Array[String]) {
val p = Sum( Number(3), Number(4))
println( p )
}
}
When I try to execute println it throws a MatchError.
Exception in thread "main" scala.MatchError: an instance of class week4.Expr$Sum
at week4.Expr.show(ExpressionProblem.scala:8)
at week4.Expr.toString(ExpressionProblem.scala:14)
at java.lang.String.valueOf(String.java:2994)
at java.io.PrintStream.println(PrintStream.java:821)
at scala.Console$.println(Console.scala:148)
at scala.Predef$.println(Predef.scala:315)
at week4.ExpressionProblem$.main(ExpressionProblem.scala:31)
at week4.ExpressionProblem.main(ExpressionProblem.scala)
you're sending an instance of your Sum class, but trying to match an instance of Sum case class. Remove classes and make case classes visible to your code:
trait Expr {
def show(e: Expr): String = e match {
case Number(a) => a.toString()
case Sum(a, b) => "(" + show(a) + "+" + show(b) + ")"
}
override def toString() = show(this)
}
case class Number(v : Int) extends Expr
case class Sum(a : Expr, b : Expr) extends Expr
object ExpressionNoProblem {
def main(args: Array[String]) {
val p = Sum(Number(3), Number(4))
println(p)
}
}
Related
I am trying to adapt this Haskell implementation of the type classes based solution of the expression problem to Scala. My current code is below. I'm having problems expressing the existential type Exp in Scala.
How can I achieve the same thing?
object ExpressionProblem {
// class Eval a where
// eval :: a -> Int
trait Eval[A] {
def eval(expr: A): Int
}
// data Exp = forall t. Eval t => Expr t
sealed abstract class Exp
case class Expr[T](val e: T)(implicit ev: Eval[T]) extends Exp
// instance Eval Exp where
// eval (Expr e) = eval e
implicit val exprInstance = new Eval[Exp] {
def eval(expr: Exp) = expr match { case Expr(e, ev) => ev.eval(e) }
}
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// here is the problem
// data BaseExp = Const Int | Add Exp Exp | Mul Exp Exp
sealed abstract class BaseExpr
case class Const(c: Int) extends BaseExpr
case class Add(lhs: Exp, rhs: Exp) extends BaseExpr
case class Mul(lhs: Exp, rhs: Exp) extends BaseExpr
// instance Eval BaseExp where
// eval (Const n) = n
// eval (Add a b) = eval a + eval b
// eval (Mul a b) = eval a * eval b
implicit val baseExprInstance = new Eval[BaseExpr] {
def eval(baseExpr: BaseExpr)(implicit e: Eval[Exp]): Int =
baseExpr match {
case Const(c) => c
case Add(lhs, rhs) => e.eval(lhs) + e.eval(rhs)
case Mul(lhs, rhs) => e.eval(lhs) + e.eval(rhs)
}
}
// TODO: Is there an easier way to make all of them implicitly convertible?
//
// The following doesn't seem to work:
//
// implicit def baseExprToExp[T <: BaseExpr](t: T): Exp = Expr[BaseExpr](t)
//
implicit def constToExp(c: Const): Exp = Expr[BaseExpr](c)
implicit def addToExp(a: Add): Exp = Expr[BaseExpr](a)
implicit def mulToExp(m: Mul): Exp = Expr[BaseExpr](m)
///////////////////////////////////////////////
// Possibly in another module/lib.
///////////////////////////////////////////////
// data SubExp = Sub Exp Exp
case class SubExpr(val lhs: Exp, val rhs: Exp)
// instance Eval SubExp where
// eval (Sub a b) = eval a - eval b
implicit val subExprInstance = new Eval[SubExpr] {
def eval(subExpr: SubExpr)(implicit e: Eval[Exp]): Int =
e.eval(subExpr.lhs) - e.eval(subExpr.rhs)
}
// Make it implicitly convertible to Exp.
implicit def subExprToExp(s: SubExpr): Exp = Expr(s)
object Test {
val exprs: List[Exp] = List(
SubExpr(Const(10), Const(3)),
Add(Const(1), Const(1))
)
}
} // ExpressionProblem
EDIT: Meanwhile I found this relevant StackOverflow answer and I adapted my code to it.
import scala.language.implicitConversions
object ExpressionProblem {
// class Eval a where
// eval :: a -> Int
trait Eval[A] {
def eval(expr: A): Int
}
//////////////////////////////////////////
// HERE'S THE MAGIC
//
// data Expr = forall t. Eval t => Expr t
trait Expr {
type T
val t: T
val evalInst: Eval[T]
}
object Expr {
def apply[T0 : Eval](t0: T0) = new Expr {
type T = T0
val t = t0
val evalInst = implicitly[Eval[T]]
}
}
// Default boxing is needed
implicit def box[T : Eval](t: T) = Expr(t)
// instance Eval Expr where
// eval (Expr e) = eval e
implicit object exprInstance extends Eval[Expr] {
def eval(expr: Expr) = expr.evalInst.eval(expr.t)
}
// data BaseExpr = Const Int | Add Expr Expr | Mul Expr Exp
sealed abstract class BaseExpr
case class Const(c: Int) extends BaseExpr
case class Add(lhs: Expr, rhs: Expr) extends BaseExpr
case class Mul(lhs: Expr, rhs: Expr) extends BaseExpr
// instance Eval BaseExpr where
// eval (Const n) = n
// eval (Add a b) = eval a + eval b
// eval (Mul a b) = eval a * eval b
implicit object baseExprInstance extends Eval[BaseExpr] {
def eval(baseExpr: BaseExpr): Int =
baseExpr match {
case Const(c) => c
case Add(lhs, rhs) => exprInstance.eval(lhs) + exprInstance.eval(rhs)
case Mul(lhs, rhs) => exprInstance.eval(lhs) + exprInstance.eval(rhs)
}
}
// Implicit conversions for all base expressions
implicit def baseExprToExpr[T <: BaseExpr](t: T): Expr = Expr[BaseExpr](t)
///////////////////////////////////////////////
// Possibly somewhere else (in the future).
///////////////////////////////////////////////
// data SubExpr = Sub Expr Exp
case class SubExpr(val lhs: Expr, val rhs: Expr)
// instance Eval SubExpr where
// eval (Sub a b) = eval a - eval b
implicit object subExprInstance extends Eval[SubExpr] {
def eval(subExpr: SubExpr): Int =
exprInstance.eval(subExpr.lhs) - exprInstance.eval(subExpr.rhs)
}
// NOTE: We don't have to provide an implicit conversion to Expr as the
// default `box` one suffices.
object Test {
val exprs: List[Expr] = List(
SubExpr(Const(10), Const(3)),
Add(Const(1), Const(1))
)
}
} // ExpressionProblem
Your problem is that you are using an extractor (unapply), but neglecting the fact that implicits are not by default exposed as part of unapply.
So this line:
def eval(expr: Exp) = expr match { case Expr(e, ev) => ev.eval(e) }
There is no case Expr(e, ev), only case Expr(e), because only e is exposed. Either write a custom extractor or find a different approach.
Scala does offer existential types of the form:
Expr[T] forSome { type T})
That has a shorthand type notation available: Expr[_]
Your code has a few more issues though:
If you define an implicit on eval, all implementors must implement an eval function with that particular signature, you can't override eval with an implementation that doesn't contain the implicit in the signature like you do in.
implicit val baseExprInstance = new Eval[BaseExpr] {
def eval(baseExpr: BaseExpr)(implicit e: Eval[Exp]): Int =
baseExpr match {
case Const(c) => c
case Add(lhs, rhs) => e.eval(lhs) + e.eval(rhs)
case Mul(lhs, rhs) => e.eval(lhs) + e.eval(rhs)
}
}
Next up you are going to need to either make T on Expr contravariant or make SubExpr also extend Exp, you have a problem here:
// instance Eval SubExp where
// eval (Sub a b) = eval a - eval b
implicit val subExprInstance = new Eval[SubExpr] {
def eval(subExpr: SubExpr)(implicit e: Eval[SubExpr]): Int =
e.eval(subExpr.lhs) - e.eval(subExpr.rhs)
}
If you will try to match the type signature, implicit e: Eval[SubExpr] can eval types that are T >: SubExpr, but what you require is a lower Exp implicit for Eval.
I am quite new to Scala and got a few unresolved problems with the following code:
object exprs{
println("Welcome to the Scala worksheet")
def show(e: Expr): String = e match {
case Number(x) => x.toString
case Sum(l, r) => show(l) + " + " + show(r)
}
show(Sum(Number(1), Number(44)))
}
trait Expr {
def isNumber: Boolean
def isSum: Boolean
def numValue: Int
def leftOp: Expr
def rightOp: Expr
def eval: Int = this match {
case Number(n) => n
case Sum(e1, e2) => e1.eval + e2.eval
}
}
class Number(n: Int) extends Expr {
override def isNumber: Boolean = true
override def isSum: Boolean = false
override def numValue: Int = n
override def leftOp: Expr = throw new Error("Number.leftOp")
override def rightOp: Expr = throw new Error("Number.rightOp")
}
class Sum(e1: Expr, e2: Expr) extends Expr {
override def isNumber: Boolean = false
override def isSum: Boolean = true
override def numValue: Int = e1.eval + e2.eval
override def leftOp: Expr = e1
override def rightOp: Expr = e2
}
I get the following errors:
Error: object Number is not a case class, nor does it have an unapply/unapplySeq member
Error: not found: value Sum
How to resolve them? Thanks in advance
In Scala case class are like class with extra goodies + some other properties.
For a normal class,
class A(i: Int, s: String)
You can not create its instance like this,
val a = A(5, "five") // this will not work
You will have to use new to create new instance.
val a = new A(5, "five")
Now lets say we have case class,
case class B(i: Int, s: String)
We can create a new instance of B like this,
val b = B(5, "five")
The reason this works with case class is because case class have an auto-created companion objects with them, which provides several utilities including an apply and unapply method.
So, this usage val b = B(5, "five") is actually val b = B.apply(5, "five"). And here B is not the class B but the companion object B which is actually provieds apply method.
Similarly Scala pattern matching uses the unapply (unapplySeq for SeqLike patterns) methods provided by companion object. And hence normal class instances do not work with pattern matching.
Lets say you wanted to defined a class and not a case class for some specific reason but still want to use them with pattern-matching etc, you can provide its companion object with the required methods by yourselves.
class C(val i: Int, val s: String) {
}
object C {
def apply(i: Int, s: String) = new C(i, s)
def unapply(c: C) = Some((c.i, c.s))
}
// now you can use any of the following to create instances,
val c1 = new C(5, "five")
val c2 = C.apply(5, "five")
val c3 = C(5, "five")
// you can also use pattern matching,
c1 match {
case C(i, s) => println(s"C with i = $i and s = $s")
}
c2 match {
case C(i, s) => println(s"C with i = $i and s = $s")
}
Also, as you are new to learning Scala you should read http://danielwestheide.com/scala/neophytes.html which is probably the best resource for any Scala beginner.
I wanted to know in a pattern matching, like in the following, do we say that the case classes are bound dynamically or statically?
sealed trait Expr
case class Lit(n: Int) extends Expr
case class Add(l: Expr, r: Expr) extends Expr
class Eval {
def eval(e: Expr): Int = e match {
case Lit(n) => n
case Add(l, r) => eval(l) + eval(r)
}
}
class Printo {
def printo(e: Expr): Unit = e match {
case Lit(n) => print(" " + n + " ")
case Add(l, r) => printo(l); print("+"); printo(r)
}
}
//Test
object TestExpr {
def main(args: Array[String]) {
val eval = new Eval
val printo = new Printo
val expr1 =
Add(Add(Lit(4), Add(Lit(7), Lit(10))),
Add(Lit(4), Add(Lit(7), Lit(10))))
val x = eval.eval(expr1)
p + "" + println(" = " + x)
}
}
How I can know if the Lit(n) or Add(l, r) are called / bound statically or dynamically?
I saw anwser here but i dont have Object Empty and i have leaf not just everthing in Node like this :
case class Node ( val e : Int ,left : BinaryTree, right : BinaryTree).
I have problem with adding Leaf as param in this def sums.
import scala.annotation.tailrec
/**
* #author emil
*/
class tree {
}
sealed abstract class BinaryTree
case class Node (left : BinaryTree, right : BinaryTree) extends BinaryTree
case class Leaf (value : Int) extends BinaryTree
object Main {
def main(args : Array[String]) {
val tree = Node(Node(Leaf(1),Leaf(3)), Node(Leaf(5),Leaf(7)));
println(tree)
sum(tree)
}
def sum(bin: BinaryTree) = {
def sums(trees: List[BinaryTree], acc: Int): Int = trees match {
case Nil => acc
case Node(l, r) :: rs => sums(l :: r :: rs, acc)
}
sums(List(bin),0)
}
}
If I understand what you want to do is something like
case Leaf(v) :: rs => sums(xs, acc+v)
May be:
def sum(bin: BinaryTree) = {
def sums(t: BinaryTree): Int = t match {
case Leaf(v) => v
case Node(l, r) => sums(l) + sums(r)
}
sums(bin)
}
val res = sum(tree)
println(res) // 16
I just create a definition in scala for Naturals, and also a PLUS operation:
abstract class Nat {
def +(other:Nat):Nat = this match {
case Zero => other
case Succ(x) => x + Succ(other)
}
}
object Zero extends Nat {
override def toString = "Zero"
}
And for the definition of Succ, i tryit not to use a Case class, for learning purposes. My first approach was:
class Succ(x: Nat) extends Nat {
override def toString = "Succ(" + x.toString + ")"
}
object Succ {
def apply(x: Nat) = new Succ(x)
def unapply(s: Succ) = Some(s.x)
}
But the compiler throws me an error
Error:( , ) value x is not a member of Succ
def unapply(s: Succ) = Some(s.x)
^
I make an explicit method for get X, and it works
class Succ(x: Nat) extends Nat {
def getX = x
override def toString = "Succ(" + x.toString + ")"
}
object Succ {
def apply(x: Nat) = new Succ(x)
def unapply(s: Succ) = Some(s.getX)
}
Why?
Constructor arguments are only visible inside the class. If you want to make it a field, you'll have to say so:
class Succ(val x: Nat) extends Nat { … }
// ^^^