在Scala中定义s-expr的惯用方法

时间:2016-01-15 00:08:23

标签: scala types s-expression

Scala如何“希望”我定义s-expr?在英语中,我们递归地定义s-expr,如下所示:“s-expr是原子或s-exprs列表。”你怎么说在斯卡拉?

我很确定这是错的:

// Scala 2.11.2
trait Sexpr

case class Atom(text: String) extends Sexpr

type List[Sexpr] = Sexpr  // To my amazement, the compiler accepts this!

val blah = Atom("blah")

def matchtest(sexpr: Sexpr): Unit = sexpr match  {
  case blah :: Nil => println(blah)  // But the compiler won't accept this
  case _ => println("no match")
}

matchtest(List(Atom("blah")))

Either可能也不适合这种情况,因为那时我必须区分LeftRight,这不是重点。

如何制作这样的递归类定义,以便与Scala的其余部分很好地协同工作?

3 个答案:

答案 0 :(得分:1)

这样的事可能

 trait Sexpr
 case class Atom(text: String) extends Sexpr
 case class SList(list: Iterable[Sexpr]) extends Sexpr

 def matchtest(sexpr: Sexpr): Unit = sexpr match {
    case SList(blah :: Nil) => println(blah)
    case _ => println("no match")
 }

答案 1 :(得分:1)

link以下列形式描述了S-expresions的Scala解析器:

abstract class SExp
case class SInt(val value : Int) extends SExp { ... }
case class SSymbol(val value : String) extends SExp { ...}
case class STrue() extends SExp { ... }
case class SFalse() extends SExp { ... }
case class SCons(val car : SExp, val cdr : SExp) extends SExp { ... }
case class SNil() extends SExp { ... }

正如另一个答案所观察到的,看起来像列表的东西实际上是一种二叉树形式,如显式SNil和SCons所示,它接受SExp类型的参数。

答案 2 :(得分:0)

问题是type List[Sexpr] = Sexpr不是您认为的意思。 List是您使用类型参数定义的类型别名,而不是 List类。因此,当您尝试将其匹配为List(类)时,它会失败。写type L[Sexpr] = Sexpr

并没有什么不同

您需要定义自己的列表类型。但是,使用scala.collection.immutable.List并不正确。根据维基百科的定义:

  

s表达式经典地定义为[1]归纳为

     
      
  1. 一个原子,或
  2.   
  3. 形式(x.y)的表达式,其中x和y是s-表达式。
  4.   

在Scala List中,x不是List(在x :: y中),不符合上述定义。 S表达式比链表更通用,并且是一种二叉树。 Scala List是S-expression的特定类型,其中每对的第一个纵坐标是原子,但并非所有S表达式都适合List

看起来应该更像这样:

sealed trait SExpr[+A]

case object NilAtom extends SExpr[Nothing]

case class Atom[+A](a: A) extends SExpr[A]

case class Pair[+A](a1: SExpr[A], a2: SExpr[A]) extends SExpr[A]

def matchTest[A](sexpr: SExpr[A]): Unit = sexpr match  {
  case Pair(a1, a2) => println("Not an Atom")
  case _ => println("Atom")
}

用法:

scala> matchTest(Pair(Atom("Test"), NilAtom))
Not an Atom

scala> matchTest(Atom("Test"))
Atom