这儿用于沉淀Scala相关交流的内容, 包括但不限:
- 通过新建一个 分享
issue
, 发起待分享的议题, 正文需简要说明分享内容或议程 - 通过指派明确分享人, 可以是发起人自己, 可以邀请他人来分享
- 通过评论来对议题进行反馈, 建议, 以或者投票
TODO
China Scala User Group
最早结识DSL, 还是因为看了Martin Flower的一篇文章叫FluentInterface, 它真正让我明白原来代码也可以这样美的.
TimeInterval meetingTime = fiveOClock.until(sixOClock);
注意, 本文中提到的DSL被狭义的等同于了Internal DSL. 言外之意, 它还有External的部分. 关于DSL更全面的内容, 还请参阅Martin Flower的专著.
以至于后来我爱上写单元测试, 很大程度要归功于mockito在DSL应用上的如火纯青.
在自己尝试着用Java写DSL的时候, 那永远摆脱不掉的.
和()
, 总让我纠结不已, 当然, 这只是个人洁癖而已.
Scala在实现DSL是很有优势的, 这在combinator.Parsers中已表明了这点, 而且在Programming Scala一书中, 作者专门用一个章节来讨论.
值得强调的是, 阻碍我们设计实现DSL的是我们自己的想象力, 而不应该是一门语言的表现力.
在此引出本文的目的: 大家来聊聊你用Scala写过的哪些DSL?
为什么叫“self-cleaning" ?cleaning表示什么?
这里介绍了 hygienic macro的概念: http://en.wikipedia.org/wiki/Hygienic_macro
主要是scheme里采用,scala 2.10里也引入了。
谁能详细阐释一下 hygienic macro 与 self-cleaning macro ?
akka 提供了 TestActorRef
帮助我们同步测试 Actor
.
def log(m: => String) = println(s"${Thread.currentThread} - $m")
def logReceived(m: => Any)(implicit self: ActorRef) = log(s"$self received: $m")
class A extends Actor {
def receive = {
case x => logReceived(x)
}
}
class B extends Actor {
private val a = context.actorOf(Props(new A))
def receive = {
case x => logReceived(x); a ! x
}
}
val a = TestActorRef(new A, "a")
log("Send a message to a")
a ! "message"
val b = TestActorRef(new B, "b")
log("Send a message to b")
b ! "message"
但运行完上面的完整代码, 打印输出结果会告诉你 :
a
发消息时, 收到消息的打印是同步执行的b
发消息时, 但a
收到消息的打印却是异步的实际开发中, 总会有如B
对A
的依赖, 那么针对B
的单元测试怎么做好呢?
我总结了部分自己以前遇到的问题,主要是scala的表现形式上的。
实际上scala是“形散而神不散”,通过一些具体例子分析这些风格的背后的习俗和规则。
scala雾中风景(0): 序 http://hongjiang.info/scala-pitfalls-0/
scala雾中风景(1): lambda表达式的缩写 http://hongjiang.info/scala-pitfalls-1/
scala雾中风景(2): 小括号与花括号 http://hongjiang.info/scala-pitfalls-2/
scala雾中风景(3): for表达式的背后 http://hongjiang.info/scala-pitfalls-3/
scala> val x : List[Any] = List(1.0,2.0,3.0)
x: List[Any] = List(1.0, 2.0, 3.0)
scala> x match {
| case l : List[Boolean] => l(0)
| case x => x
| }
<console>:10: warning: non-variable type argument Boolean in type pattern List[Boolean] is unchecked since it is eliminated by erasure
case l : List[Boolean] => l(0)
^
res0: Any = 1.0
import scala.reflect.runtime.universe._
class Def[C: TypeTag] {
def unapply[X: TypeTag](c: X): Option[C] = {
if (typeOf[X] <:< typeOf[C]) Some(c.asInstanceOf[C]) else None
}
}
val BooleanList = new Def[List[Boolean]]
x match {
case BooleanList(l) => l
case x => x
}
假定, tail -f log
会不断输出类似下面日志内容
2013-12-03 10:20:26,889 [nioEventLoopGroup-2-3] DEBUG i.n.handler.logging.LoggingHandler - [id: 0x456ea7b0, /10.68.199.85:36714 => /10.125.48.164:7769] WRITE(42B)
+-------------------------------------------------+
| 0 1 2 3 4 5 6 7 8 9 a b c d e f |
+--------+-------------------------------------------------+----------------+
|00000000| 34 30 31 0a 76 69 61 3a 74 63 70 3a 2f 2f 31 30 |401.via:tcp://10|
|00000010| 2e 36 38 2e 31 39 39 2e 38 35 3a 33 36 37 31 34 |.68.199.85:36714|
|00000020| 0a 6d 69 64 3a 32 20 30 0a 0a |.mid:2 0.. |
+--------+-------------------------------------------------+----------------+
2013-12-03 10:20:26,889 [nioEventLoopGroup-2-3] DEBUG i.n.handler.logging.LoggingHandler - [id: 0x456ea7b0, /10.68.199.85:36714 => /10.125.48.164:7769] FLUSH
2013-12-03 10:20:27,089 [nioEventLoopGroup-2-3] DEBUG i.n.handler.logging.LoggingHandler - [id: 0x456ea7b0, /10.68.199.85:36714 => /10.125.48.164:7769] RECEIVED(406B)
现, 需要写段 scala
脚本, 使得 tail -f log | scala script.scala
后输出:
2013-12-03 10:20:26,889 /10.68.199.85:36714 => /10.125.48.164:7769 WRITE(42B)
401
via:tcp://10.68.199.85:36714
mid:2 0
2013-12-03 10:20:26,889 /10.68.199.85:36714 => /10.125.48.164:7769 FLUSH
2013-12-03 10:20:27,089 /10.68.199.85:36714 => /10.125.48.164:7769 RECEIVED(406B)
你实现了吗?
嗯, 不错! 然我们提升一点难度, 让你的脚本支持一个 关键字 的参数, 使得执行tail -f log | scala script.scala "401"
后输出上面的内容不变, 而执行tail -f log | scala script.scala "400"
后则输出:
2013-12-03 10:20:26,889 /10.68.199.85:36714 => /10.125.48.164:7769 WRITE(42B)
2013-12-03 10:20:26,889 /10.68.199.85:36714 => /10.125.48.164:7769 FLUSH
2013-12-03 10:20:27,089 /10.68.199.85:36714 => /10.125.48.164:7769
请务必用函数的思维来实现你的脚本!
缘起 @fujohnwang 在微薄上转发的这条微薄http://weibo.com/1642316384/zwZpTDnSp, 感谢 @argan 联系到19lou的朋友, 让我们有机会做一次交流.
请大家通过回复评论表明参加的意愿和期待的议题.
当然, 希望借此机会做些议题分享的朋友也可在回复中注明.
scala类型系统:1) 类型与类 http://hongjiang.info/scala-type-and-class/
scala类型系统:2) classOf与getClass方法的差异 http://hongjiang.info/scala-type-system-classof-and-getclass/
scala类型系统:3) 单例类型 http://hongjiang.info/scala-type-system-singleton-type/
scala类型系统:4) 内部类,路径依赖类型&类型投影 http://hongjiang.info/scala-type-system-inner-type-and-type-projection/
《scala中的函数与闭包》
slideshare上:http://www.slideshare.net/hongjiang/scala-functionandclosures
或这里:http://vdisk.weibo.com/s/znOJO
ppt和pdf打开错误,请协助。
这儿有道题, 从实际的项目中简化而来:
case class User(id: Long, nickname: String, password: String, mobile: String)
object Users {
def userBy(mobile: String): Option[User] =
if (mobile == "01234567890") Some(User(1L, "allen", "******", "01234567890")) else None
def authenticate(mobile: String, password: String): Either[User, String] = ???
}
assert(Users.authenticate("allen", "******") == Right("Invalid mobile"))
assert(Users.authenticate("01234567891", "******") == Right("Mobile not found"))
assert(Users.authenticate("01234567890", "??????") == Right("Invalid password"))
assert(Users.authenticate("01234567890", "******") == Left(User(1L, "allen", "******", "01234567890")))
请根据assert
提示实现authenticate
.
scala类库中的api陷阱(1): LinkedList.append
http://hongjiang.info/scala-api-pitfalls-1/
我下周准备做一次 spray-routing 的分享。
它的基本原理,怎么实现DSL的。
注意, 以下代码都以在 scala 2.10.2 jdk 1.7中编译运行为讨论前提
trait A {
case class B(i: Int)
}
class C extends A {
def !(a:Any) = a match {
case B(0) => println("never be here")
case b: B => println("never be here")
case x => println(s"Oops, received $x")
}
}
class D extends A {
new C ! B(0)
}
new D
上面代码在 scala REPL 中运行, 打印输出的结果是Oops, received B(0)
, 问题就出来了:
为什么
case B(0)
和case b: B
都没有能够匹配上?
问题的答案可以从scalac -Xprint:typer
的结果中找到:
class C extends AnyRef with A {
def <init>(): C = {
C.super.<init>();
()
};
def !(a: Any): Unit = a match {
case (i: Int)C.this.B(0) => scala.this.Predef.println("never be here")
case (b @ (_: C.this.B)) => scala.this.Predef.println("never be here")
case (x @ _) => scala.this.Predef.println(scala.StringContext.apply("Oops, received ", "").s(x))
}
};
class D extends AnyRef with A {
def <init>(): D = {
D.super.<init>();
()
};
new C().!(D.this.B.apply(0))
}
在new C ! B(0)
中B
的类型是D.this.B
, 而在C.!(a: Any)
的match
中B
的类型都是C.this.B
那么答案也就很明确了, 引用之 @hongjiang 的论断:
这个 case 类是个内部类,这点性质与java一样,它一定要存活在它的外部对象实例内,外部实例不同,它们也不同
因此, 在实际应用中, 请谨慎使用这种用法, 除非你有特别好的理由
进一步的思考: Scala 编译器是如何实现的呢?
答案在这里, 你找找看:)
class Usecase extends Actor {
val rel = context.actorSelection("../relative/path")
def receive = ???
override def postStop() {
rel ! "message" // failure
}
}
杭州余杭区文一西路969号 阿里巴巴西溪园区 2号楼 1-13 凤凰山庄
针对7月份的阿里技术嘉年华上编程语言专场,大概40分钟,准备分享的议题如下:
比如 List(1,2,2,3).distinct 可以把集合里的重复元素去掉。这样比用Set操作再做类型转换要简单些
2014年上半年华东地区scala爱好者交流,这次活动的地点仍由“看处方”公司提供。
地点:上海市静安区昌平路990号8号楼102
7号线昌平路站5号口出来,沿昌平路往西走约7、8分钟。明圭都市工业园后面。
时间:5.31号下午1点30开始
活动安排:
现已完成前3篇
翻译 monads-are-elephants 第三部分 http://hongjiang.info/monads-are-elephants-part3-chinese
翻译 monads-are-elephants 第二部分 http://hongjiang.info/monads-are-elephants-part2-chinese
翻译 monads-are-elephants 第一部分 http://hongjiang.info/monads-are-elephants-part1-chinese
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.