Duarte M.
Duarte M.

Reputation: 35

Scala: recursive value listHuman needs type

Why is this function giving me the following error:

recursive value listHuman needs type

def setHumanResources(physicalResources: List[Physical], totalHumanResources: List[Human]): List[Human] = {
    val listHuman = physicalResources.map{pr => totalHumanResources.find(_.handles.contains(pr.post)).filterNot(a=>listHuman.contains(a))}
    return listHuman
}

I tried to do this, but it gives me another error:

val listHuman: List[Human] = physicalResources.map{pr => totalHumanResources.find(_.handles.contains(pr.post)).get}.filterNot(human=>listHuman.contains(human))

forward reference extends over definition of value listHuman

Upvotes: 0

Views: 2682

Answers (3)

rogue-one
rogue-one

Reputation: 11577

The premises here is to have setHumanResourcesreturn a unique/distint list of Human objects. The code tries this by doing filterNot(a=>listHuman.contains(a)) in definition of listHuman and thus recursively referring to listHuman while defining listHuman in semantically illegal way. This de-duping can be achieved properly by the following ways.

  • convert the List to Set and convert it back to List to remove duplicates like listHuman.toSet.ToList. for this method to work the Human object have property identity defined by overriding equals method. so the code will now look like

    def setHumanResources(physicalResources: List[Physical], totalHumanResources: List[Human]): List[Human] = {
          val listHuman = physicalResources.map{pr => totalHumanResources.find(_.handles.contains(pr.post))
          listHuman.toSet.toList
    }
    

    A Demo for a sample class of Human is shown below.

     scala> class Human(val firstName: String, val lastName: String) {
     |   override def toString = this.firstName
     |   override def equals(that: Any): Boolean = that match {
     |      case that: Human if that.firstName == this.firstName => true
     |      case _ => false
     |   }
     | }
    defined class Human
    
    scala> List(new Human("Peter", "Parker"), new Human("Peter", "Quill")).toSet.toList
    res14: List[Human] = List(Peter)
    
  • If the class Human cannot have object equality defined in it by overriding equals method then follow this approach. considering each Human can be uniquely identified by say two properties property1 and property2. the listHuman can be deduped by the following expression. For our previously defined Human class if we want to de-dupe on both firstName and lastName properties, the code would be like below.

    listHuman.groupBy(x => (x.firstName, x.lastName)).map(_._2.head)
    

    so the new method definition becomes

      def setHumanResources(physicalResources: List[Physical], totalHumanResources: List[Human]): List[Human] = {
           val listHuman = physicalResources.map{pr => 
           totalHumanResources.find(_.handles.contains(pr.post))
           listHuman.groupBy(x => (x.property1, x.property2) ).map(_._2.head)
       }
    

Upvotes: 0

Tanjin
Tanjin

Reputation: 2452

It seems like you want to do a foldLeft, does this work?

def setHumanResources(physicalResources: List[Physical], totalHumanResources: List[Human]): List[Human] = {
  physicalResources.foldLeft(Set.empty[Human]) { (l, pr) =>
    val applicableHuman = totalHumanResources.find(_.handles.contains(pr.post))
    l ++ applicableHuman
  }.toList
}

Upvotes: 1

Zernike
Zernike

Reputation: 1766

This error means that constant value or variable is used before its declaration. For example

    val y = x + 2
    val x = 5

What wrong with your code is you try to define constant value with itself. It's impossible by definition of constant. To build recursion use def.

Upvotes: 1

Related Questions