Clojure到Scala的翻译:L系统更新



我正试图为一个类项目建模一个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,而kkeytype,而不是++运算符所期望的Seq[keytype]

现在,对于第二个问题,除非更改参数的顺序,否则无法使用translate函数foldRight

您可以选择foldLeftreverse:

  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)
}

最新更新