Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

An example of functional programming in scala

I'm studying scala. It's very promising, thanks to Odersky and all the other authors for their great work.

I took a euler problem (http://projecteuler.net/) to have a more-then-minimal example. And I'm trying to go the functional way. So this is not a "please answer me immediatly or my boss will kill me" but a "please if you've got time, can you help a imperative language programmer to take a journey in the functional world?"

Problem: I want a class for poker hands. A poker Hand is composed by a number of Card, from 0 to 5. I'd like to build the list of Cards one and for all, that is: my Hand class will be immutable, if I want to add a card, then I create a new Hand object. So I need a collection of Card that can be created as "val", not as var. First step: constructors, one for each number of cards. But Card's collection is handled in each constructor, so I must have it as var!

Here's the code, Card class is simply a Suit and a Value, passed to constructor as a string ("5S" is the 5 of spades):

class Hand(mycards : List[Card]) {
  // this should be val, I guess
  private var cards : List[Card] = {
    if (mycards.length>5)
      throw new IllegalArgumentException(
        "Illegal number of cards: " + mycards.length);
    sortCards(mycards)
  }

  // full hand constructor
  def this(a : String, b : String, c : String, d : String, e : String) = {
      this(Nil)

      // assign cards
      val cardBuffer = new ListBuffer[Card]()
      if ( a!=null ) cardBuffer += new Card(a)
      if ( b!=null ) cardBuffer += new Card(b)
      if ( c!=null ) cardBuffer += new Card(c)
      if ( d!=null ) cardBuffer += new Card(d)
      if ( e!=null ) cardBuffer += new Card(e)
      cards = sortCards(cardBuffer.toList)
  }
  // hand with less then 5 cards
  def this(a : String, b : String, c : String, d : String) = this(a,b,c,d,null)
  def this(a : String, b : String, c : String) = this(a, b, c, null)
  def this(a : String, b : String) = this(a, b, null)
  def this(a : String) = this(a, null)
  def this() = this(Nil)

/* removed */
}

Do you know how to make it the true functional way? Thanks.

PS: if you really want to know, it's problem 54.

like image 635
Ratman Avatar asked Aug 10 '11 08:08

Ratman


1 Answers

My answer is not about functional aspect of scala, but your code is possible to write shortly using scala sugar:

class Hand(val mycards: List[Card]) {
  require (mycards.size <= 5,"can't be more than five cards")
  def this(input: String*) = { 
    this(input.map(c => new Card(c)).toList)
  }
}

input: String* in auxiliary constructor says that you can have variable number of arguments (even thousand of strings). I'm getting input and invoke creation for each new Card with map function, and then pass result to parent constructor which has it's own requirement. (BTW, mapping from string to Card can be done anonymously, in that manner: this(input.map(new Card(_)).toList))

class Hand(val mycards: List[Card]) {...

Is equable to

class Hand(cards: List[Card]) {
val mycards = cards 
...

From now on, if you will try to create more than five cards in hand you'll get java.lang.IllegalArgumentException:

scala> class Card(s: String) {println("Im a :"+s)}
defined class Card

scala> new Hand("one","two","three","four","five","six")
Im a :one
Im a :two
Im a :three
Im a :four
Im a :five
Im a :six
java.lang.IllegalArgumentException: requirement failed: can't be more than five card
    at scala.Predef$.require(Predef.scala:157)
    at Hand.<init>(<console>:9)
like image 126
om-nom-nom Avatar answered Oct 11 '22 14:10

om-nom-nom