我正试图为一个类项目建模一个L系统,但在使用了几个月的Clojure之后,我很难用Scala的reduce/fold和typesystem来实现这一目标。
在Clojure,我会写
user> (defn update-state [translation-map, state]
(mapcat #(get translation-map %1 [%1]) state))
user> (def translations {"a" ["b", "a", "b"]})
user> (update-state translations ["a"])
["b", "a", "b"]
这个技巧之所以有效,是因为我隐式定义了(update-state "b") => ["b"]
,并且我使用clojure.core/mapcat
来处理concat
将转换的值放在一起。
因此,如果我们应用这个运算两次,我们就会看到示例L系统的行为与预期一致。。
user> (->> ["a"]
(update-state translations)
(update-state translations))
["b", "b", "a", "b", "b"]
我在那里的Scala尝试是
package me.arrdem.planter;
import scala.collection.mutable.{HashMap,LinkedList};
class LSystem[keytype,fntype] {
var _invoke_map = HashMap[keytype,fntype]()
var _tr_map = HashMap[keytype,Seq[keytype]]()
def translate(s:Seq[keytype], k:keytype) : Seq[keytype] = {
s ++ (if(_tr_map contains(k)) _tr_map.get(k) else (k))
}
def step(s:Seq[keytype]) : Seq[keytype] = {
s foldRight(LinkedList[keytype]())(translate)
}
}
在我看来,除了类型检查器抱怨之外,这应该是有效的
ERROR: type mismatch; found : Seq[Any] required: Seq[keytype] : line 9
ERROR: type mismatch; found : keytype required: scala.collection.GenTraversableOnce[?] : line 9
ERROR: type mismatch; found : keytype required: scala.collection.GenTraversableOnce[?] : line 9
现在,当我读到这篇文章时,隐含的错误是,不知何故,表达式(if(_tr_map contains(k)) _tr_map.get(k) else (k))
被类型推断为Seq[Any]
,而不是Seq[keytype]
。
由于这两个结果是1)找到了关键字->Seq[keytype]
和2)没有找到关键字->singleton tuple (k)
,这怎么可能?我该如何更正?
干杯
尝试替换:
s ++ (if(_tr_map contains(k)) _tr_map.get(k) else (k))
带有:
s ++ _tr_map.get(k).getOrElse(Seq[keytype](k))
您的问题是HashMap.get(k)
返回Option
,而k
是keytype
,而不是++
运算符所期望的Seq[keytype]
。
现在,对于第二个问题,除非更改参数的顺序,否则无法使用translate函数foldRight
。
您可以选择foldLeft
和reverse
:
def step(s: Seq[keytype]): Seq[keytype] = {
s.foldLeft(Seq[keytype]())(translate)
}
或者将translate
功能更改为:
def translate(k:keytype, s:Seq[keytype]) : Seq[keytype] = {
s ++ _tr_map.get(k).getOrElse(Seq[keytype](k))
}
然后你可以foldRight
:
def step(s: Seq[keytype]): Seq[keytype] = {
s.foldRight(Seq[keytype]())(translate)
}
// Seq needs to be 'right' parameter : (foldRight means accumulator is right)
def translate(k: keytype, s:Seq[keytype]) : Seq[keytype] = {
s ++ (if(_tr_map contains(k)) _tr_map.get(k).get else Seq(k))
// Hashmap.get returns an option so you need another get
// in else condition you need Seq(k)
}
def step(s:Seq[keytype]) : Seq[keytype] = {
s.foldRight(Seq[keytype]())(translate)
// need dotted syntax for foldRight
// or (s foldRight Seq[keytype]()) (translate)
}