What have you found for these years?

2009-03-15

印星星

[begin updated2]
又改了一下,因為想起來還有 concat 可以用。
不過我幹嘛一直改這個啊?又不是個什麼很重要的程式。
[end]

*

想說讀一下 scala, 然後順便寫寫題目好了,
就拿最近 programming 連線板上的印星星...
目標是:
  3
345
34567
345
3

我在猶豫要不要把程式碼貼出來,還是看 gist 就好了。
http://gist.github.com/79112
程式碼貼在最後面好了,有貼佔版面,不貼又怪怪的。

scala 寫起來的感覺嘛,還滿難形容的。好像該有的都有,
可是寫起來就是覺得怪怪的。該說果然是混血的語言嗎?
像是 foldRight, 為什麼是用 {} 接 function 啊...
而且 lambda 寫起來也有種奇妙的感覺,好像浮在半空中?
list comprehension 更是囉唆到了極點。

不過去掉這些感覺怪怪的地方,比方說習慣了,那 scala
倒是真的不錯。至少其他地方我覺得用起來都還滿直覺的。
像是 type inference 讓你 type 可寫可不寫,
every value is an object;
every function is a value.
這些特性是還不錯。就是關鍵字真的略嫌多了點...
有種 java 的 verbose 味在 :s

第二個寫的是 haskell, 兩三下就寫好了。
而且感到非常的暢快...(痛哭流涕)
我只能說,就以 functional programming 的角度而言,
應該還是 haskell 寫起來最舒適吧?
翻譯過來的時候,快速砍掉一堆 scala 多餘的描述,
剩下的就是 haskell 了。

第三個寫的是 ruby, 不多說了,就是秒殺 -_-b
畢竟這我太熟了...

第四個是 python, 決定用 python 3.0 試試。
然後我發覺他跟 scala 各有不同囉哩八唆的地方 = =
self, self, self, self, self, selfish... -_-b
最讓我感到不爽的,則是 lambda 居然只能寫一個 expression.
明明就不夠 functional 沒辦法把所有東西都寫成一個 expression,
這樣 lambda 變得好殘廢啊.......
而且寫錯什麼,都只說 invalid syntax.
哪像 scala 都會很清楚告訴你 expected 什麼,got 什麼。

還有,List#reverse 居然不會 copy, 還回傳 nothing...
這 functional 個屁屁屁啊 orz

[begin updated1]
經留言提醒,reverse list 用 list[::-1]
順手也改了底下的 code 和 gist.
這樣真的好多了,原本那樣 copy 又 reverse 實在是很蠢。
晚點等 ocaml/clojure 寫完再看看 [] 還有些啥用法...
[end]

也就是說,python 讓我覺得異常失望 orz

晚了累了,下一個試 ocaml 和 clojure.

// Star.scala
class Star(max: Int){
val mid = max / 2 + 1
def row(n: Int): List[Int] =
for (i <- List.range(mid, max + mid - 2 * (mid - n - 1).abs)) yield i

val result =
for (i <- List.range(0, max)) yield
List.range(0, (mid - i - 1).abs).map{s=>' '} ++ row(i)

override def toString: String =
result.foldRight(""){
(l, s) => "\n" + l.mkString + s
}.drop(1).toString
}

println(new Star(5))
-- Star.hs
module Main where

star :: Integer -> String
star max = tail $ to_s rectangle where
rectangle :: [[String]]
rectangle = [spaces i ++ row i | i <- [0..max-1]]
spaces i = map (\x->" ") [0..abs (mid-i-1) - 1]
mid = max `div` 2 + 1
row :: Integer -> [String]
row n = [ show i | i <- [mid..( max+mid-2 * abs (mid-n-1) ) - 1] ]
to_s = foldr (\l s -> ("\n" ++ concat l ++ s)) ""

main = putStrLn $ star 5
# Star.rb
class Star
attr_reader :max, :mid, :result
def initialize max
@max = max
@mid = max / 2 + 1
@result = (0...max).map{ |i| ([' '] * (mid-i-1).abs) + row(i) }
end

def row n
(mid...max + mid - 2 * (mid - n - 1).abs).to_a
end

def to_s
result.inject(''){ |s, l| "\n" + l.join + s }[1..-1]
end
end

puts Star.new((ARGV.first || 5).to_i)
# Star.py
from functools import reduce

class Star:
def __init__(self, max):
self.max = max
self.mid = max // 2 + 1
self.result = [ [' '] * abs(self.mid-i-1) +
list(map(lambda x: str(x), list(self.row(i)))) for i in range(max) ]

def row(self, n):
return range(self.mid, self.max + self.mid - 2 * abs(self.mid - n - 1))

def __str__(self):
return reduce(lambda s,l: "\n"+''.join(l)+str(s), self.result, '')[1:]

print(Star(5))

30 retries:

jaiyalas said...

老大, 你這篇的部份(80%~100%)內容
借我轉一下唷? 可否?

Lin Jen-Shin (godfat) said...

註明作者或是出處就行啦

jaiyalas said...

作者是劍心
我怎可能不註明?

遑論,
轉貼這文章完全是炫耀心理呀 XD

Lin Jen-Shin (godfat) said...

來 PLT 玩玩吧 XD

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...
This comment has been removed by a blog administrator.
Lin Jen-Shin (godfat) said...

1. What's missing in the Scala code?
It runs fine on my computer.

2. I am not familiar with Python,
just translating the algorithm
in the Scala code above to Python.
This is my first pythoning time,
so the result is a little ugly I know,
haha.

I'll try to reproduce your Python code later.
Thanks for your example!

Lin Jen-Shin (godfat) said...

You have to manually translate your space to &nbsp;
I can't help with this, this is blogger's behavior.

Anonymous said...

5 error: 'val' expected but identifier found.
def row(n: Int): List[Int] = for (i <- List.range(mid, max + mid - 2 * (mid - n - 1).abs)) yield i
^
:15 error: illegal start of simple pattern
}
^
:14 error: '<-' expected but '}' found.
}.drop(1).toString
^
three errors found

Anonymous said...
This comment has been removed by a blog administrator.
Lin Jen-Shin (godfat) said...

Hmm... I can't figure out why there are such errors.
Here's my Scala version:

godfat ~/p/t/star> scala -version
Scala code runner version 2.7.3.final -- Copyright 2002-2009, LAMP/EPFL

Perhaps you are running older Scala?

Lin Jen-Shin (godfat) said...

You can tell me how to reverse a list with copy in a straightforward way.

Anonymous said...

scala -version
Scala code runner version unknown version -- (c) 2002-2006 LAMP/EPFL

Anonymous said...

why would I? It seems everyone is expert

Anonymous said...

the code
http://gist.github.com/79391

run with python 2.x

Lin Jen-Shin (godfat) said...

Glad to know you have a world full of experts, congratulation!

And what I wish to archive,
is to precess lists and print final result,
not printing along the way.

Thanks for your gist anyway.
It's easier to read a lot now.

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...

to precess lists and print final result, not printing along the way.

1. put the join in your client code for printing only, not in the closure

2. return result instead of return ''.join(result)

Lin Jen-Shin (godfat) said...

Thanks for your tips, I've updated blog post and gist.

update reverse list

Now I can remove copy and stupid reverse method,
it's much much better now.

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...

the code is worse as my assembly code

Lin Jen-Shin (godfat) said...

It's the algorithm in all Star programs above.
I'm simply translating it to all PL.
In Haskell (the most clean case), it's:

to_s = foldr (\l s -> ("\n" ++ foldr (\i s -> i ++ s) s l)) ""

It's straightforward in functional programming.

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...
This comment has been removed by a blog administrator.
Lin Jen-Shin (godfat) said...

I've never said that.
I said it's just straightforward,
and it just jumped out from my brain.
I am not trying to write a perfect Star program.

But you remind me that there's concat in Haskel.

to_s = foldr (\l s -> ("\n" ++ concat l ++ s)) ""

I am thinking how to port this to Python.
Below didn't concat the last line in result.

reduce(lambda s,l: "\n" + ''.join(l) + s.__str__(), self.result[::-1])[1:]

Anonymous said...

besides, str(i) is much better than i.__str__()

Lin Jen-Shin (godfat) said...

And you are really really impolite.

Anonymous said...
This comment has been removed by a blog administrator.
Anonymous said...
This comment has been removed by a blog administrator.
Lin Jen-Shin (godfat) said...

I start to think talking to you are wasting my time, so comments closed.



All texts are licensed under CC Attribution 3.0