简体   繁体   English

使用折叠在树上实现地图

[英]Implementing map on a tree using fold

I am trying to implement a map using fold. 我正在尝试使用fold实现地图。 I could do so in Haskell 我可以在Haskell这样做

 data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show)


 foldTree :: Tree a -> b -> (b -> a -> b -> b) ->  b   
 foldTree EmptyTree d _ = d
 foldTree (Node a l r) d f =  f (foldTree l d f)  a  (foldTree r d f)


 mapTree :: Tree a -> ( a -> b) -> Tree b
 mapTree tree f = foldTree tree EmptyTree (\l n r -> Node (f n)  l  r)

However when I tried to port it to Scala, I am a bit stuck 但是,当我尝试将其移植到Scala时,我有点卡住了

sealed trait Tree[+A]
case object EmptyTree extends Tree[Nothing]
case class Node[A](value: A , left: Tree[A], right: Tree[A]) extends Tree[A]


def fold[A, B](t:Tree[A] , z:B)(f:(B,A,B) => B) : B = t match {
    case EmptyTree => z 
    case Node(x,l,r) => f ( fold( l , z )(f) , x , fold( r , z )(f) )   
  }

  def map(tree:Tree[Int])(f:Int=>Int) : Tree[Int] = fold(tree , EmptyTree)((l,x,r) => Node(f(x),l,r))

The compiler complains that it is expecting an EmptyTree in function I pass to fold. 编译器抱怨说我希望传递给函数的EmptyTree可以折叠。

fold(tree , EmptyTree)((l,x,r) => Node(f(x),l,r))

The return type for the Map is Tree so I would have expected this to work. Map的返回类型是Tree,所以我希望它能正常工作。 Any suggestions ? 有什么建议么 ?

Try to write your last line as 尝试将您的最后一行写为

def map(tree:Tree[Int])(f:Int=>Int) : Tree[Int] = fold(tree , EmptyTree:Tree[Int])((l,x,r) => Node(f(x),l,r))

Scala's type inference is very limited compared to haskell, in this case it tries to infere type of fold from it's arguments left to right, and incorectly decides that result type of fold should be EmptyTree and not the Tree[Int] . 与haskell相比,Scala的类型推断非常有限,在这种情况下,它试图从其参数从左到右推断出fold类型,并且错误地确定折叠的结果类型应为EmptyTree而不是Tree[Int] Usually adding auxilary constructor to the companion object of the parent type helps in this situation a bit, for instance in the Option object there's a constructor 通常将辅助构造函数添加到父类型的伴随对象中会对此有所帮助,例如,在Option对象中有一个构造函数

def empty[A]: Option[A] 

which returns the parent type. 返回父类型。

As an alternative to @vitalii's solution, make the type parameters to fold explicit: 作为@vitalii解决方案的替代方法,使类型参数fold显式:

def map(tree: Tree[Int])(f: Int=>Int): Tree[Int] =
  fold[Int, Tree[Int]](tree, EmptyTree)((l, x, r) => Node[Int](f(x), l, r))
  //   ^^^^^^^^^^^^^^

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM