Sunday, November 6, 2011

Learning Scala: doing Scala exercise from Haskell's example

Authored by Win Myo Htet

In my previous post, I complain about the lack of exercise from the Scala book for the learner to do exercise. So, I have been thinking of getting myself some exercise and talk with my friend who has inspired me to try functional programming. I have done the mandatory fizzbuzz interview on him regarding Haskell. I have updated his Haskell solution along with my Scala one in the previous post. I tell him about my plight and he blesses me with the following Haskell code from here.

type Point = (Float,Float)
type Color = (Int,Int,Int)
type Polygon = [Point]

writePoint :: Point -> String 
writePoint (x,y) = (show x)++","++(show y)++" "

writePolygon :: (Color,Polygon) -> String 
writePolygon ((r,g,b),p) = "<polygon points=\""++(concatMap writePoint p)++"\" style=\"fill:#cccccc;stroke:rgb("++(show r)++","++(show g)++","++(show b)++");stroke-width:2\"/>"

writePolygons :: [(Color,Polygon)] -> String 
writePolygons p = "<svg xmlns=\"http://www.w3.org/2000/svg\">"++(concatMap writePolygon p)++"</svg>"

colorize :: Color -> [Polygon] -> [(Color,Polygon)] 
colorize = zip.repeat

rainbow@[red,green,blue,yellow,purple,teal] = map colorize [(255,0,0),(0,255,0),(0,0,255),(255,255,0),(255,0,255),(0,255,255)]

main = do
writeFile "tut0.svg" $ writePolygons (blue [[(100,100),(200,100),(200,200),(100,200)],
                                            [(200,200),(300,200),(300,300),(200,300)]])

The code has been modified to be able to compile as filename.hs. What does the code do? It creates a svg file, which draw a rectangluar with blue line. Since I have already provided the original link, I won't be going into it in detail. Let's try to implement our Scala equivalent.

The first three lines of the Haskell code is pretty much class declaration in Scala with Polygon having a List of Point.

In Haskell, the syntax structure for method is that method signature come first and then method body come next with leading method name. Haskell is space sensitive like Python.  In method signature, methodName::input->outPut is the format.

writePoint is getting the value of Point in String format and it is pretty much Point's toString. 

writePolygon is getting a String with the values of Color and Polygon embedded in some XML format. So basically, Color and Polygon does not have dedicated method like Point to print their value. Their values have been constructed in the line.


writePolygons create the XML String with the parameter being List of (Color,Polygon) Tuple, which get feed into writePolygon individually for the respective XML string result.

Ok, that's good enough to try some Scala, let's create three classes: Point, Color and Polygon. Since their values are always printed, we will override toString and return the desire format. It is straight forward to do that for Point and Color. Polygon has the List Collection of Point as its value and we will be using foldRight to print out the desire value. Now that overriding toString is done, we will just drop these object into our writePolyGon and writePolyGons method.

That is easy. Here comes more interesting part. Before I start coding, when I was look at colorize and my friend asks me to read it, I said that it is currying and he said that it is correct. He said that the method definition's expression has dropped their parameter since it is inferred. Thus, colorize=zip.repeat. Now, I have to read a bit at the site to see what they do so that I know how to code them in Scala. It is said that repeat make use of Haskell's lazy pattern. Ok, it seems alright, Scala also has lazy val. Basically, repeat wait for the the next parameter List and create a new List of the size of the paramter List and fill it with the first parameter . zip zipps'em up these two. Sound good.

I don't know rainbow@ line. My friend is gone now. But it seems that it is a list of partial function, functional literal, created by colorize by having an initialize color value. I skip to the last line and read it and it appears so. Since, my Scala knowledge is quite weak, I don't recall anyway to emulate the Haskell's rainbow@ line. (I will be very happy to learn if there is a way). So, I won't be having rainbow for now :(  but blue only. So, let's see what I have done.

class Point(val x:Float,val y:Float){
override def toString()=x+","+y
}

class Color(val r:Int,val g:Int,val b:Int){
override def toString()=r+","+g+","+b
}

class Polygon(val pList:List[Point]){
override def toString()=pList.foldRight(""){(x,s)=>x+" "+s}
}

def writePolyGon(c:Color,p:Polygon):String="<polygon points=\""+p+"\" style=\"fill:#cccccc;stroke:rgb("+c+");stroke-width:2\"/>"

def writePolyGons(tList:List[(Color,Polygon)]):String
={"<svg xmlns=\"http://www.w3.org/2000/svg\">"+
tList.foldLeft(""){(s,x)=>s+writePolyGon(x._1,x._2)}+
"</svg>"
}

def colorize(c:Color)(pList:List[Polygon]):List[(Color,Polygon)]
={
lazy val repeat=(for(p<-pList)yield(c,p)).toList
repeat
}

val blue=new Color(0,0,255)
val blue_ = colorize(blue)_

val rectangle1=new Polygon(List(new Point(100,100),new Point(200,100),new Point(200,200),new Point(100,200)))
val rectangle2=new Polygon(List(new Point(200,200),new Point(300,200),new Point(300,300),new Point(200,300)))

printToFile("tut0ofScala.svg",writePolyGons(blue_((List(rectangle1,rectangle2)))))



def printToFile(fileName:String, content:String):Unit
={printToFile(new java.io.File(fileName))(p=>p.println(content))}

/*http://stackoverflow.com/questions/4604237/how-to-write-to-a-file-in-scala*/
def printToFile(f :java.io.File)(op : java.io.PrintWriter => Unit)
={  val p=new java.io.PrintWriter(f)
try{ op(p)} finally{p.close()}
}

I have created 2 rectangle objects instead of feeding non descriptive data. Scala not having the file writing mechanism as part of the standard library does not also help. I have to run to SO for that as it can be seen in the comment line. Definitely, my Scala code will have a lot of room for improvement and I sure want to learn them.



Authored by Win Myo Htet

No comments:

Post a Comment