我正在尝试为一个类项目建模一个L系统,但是我正在努力使用Scala的reduce / fold和类型系统来实现这个目标,经过几个月的Clojure。
在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)找不到密钥 - >单身元组(k)
,这怎么可能,我该如何纠正呢?
干杯
答案 0 :(得分:2)
尝试更换:
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]
运算符所期望的++
现在针对您的第二个问题,除非您更改参数的顺序,否则不能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)
}
答案 1 :(得分:1)
// 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)
}