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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With