This post originated from an RSS feed registered with Scala Buzz
by Caoyuan Deng.
Original Post: An Example Syntax in Haskell, Erlang and Scala
Feed Title: Blogs about Scala from Caoyuan
Feed URL: http://blogtrader.org/page/dcaoyuan/feed/entries/atom?tags=scala
Feed Description: Blogs about Scala from Caoyuan Deng
It's actually my first time to write true Scala code, sounds strange? Before I write Scala code, I wrote a Scala IDE first, and am a bit familiar with Scala syntax now. And I've got about 1.5 year experience on Erlang, it began after I wrote ErlyBird.
Now it's time to write some real world Scala code, I choose to port Paul R. Brown's perpubplat blog engine, which is written in Haskell. And I have also some curiosities on how the syntax looks in Erlang, so I tried some Erlang code too.
Here's some code piece of entry module in Haskell, Erlang and Scala:
Original Haskell code piece
empty :: Model
empty = Model M.empty M.empty M.empty [] 0
build_model :: [Item] -> Model
build_model [] = empty
build_model items = Model (map_by permatitle sorted_items)
bid
(build_child_map sorted_items)
(sorted_items)
(n+1)
where
sorted_items = sort_by_created_reverse items
bid = (map_by internal_id sorted_items)
n = fst . M.findMax $ bid
build_child_map :: [Item] -> M.Map Int [Int]
build_child_map i = build_child_map_ (M.fromList $ (map (\x -> (internal_id x,[])) i)) i
-- Constructed to take advantage of the input being in sorted order.
build_child_map_ :: M.Map Int [Int] -> [Item] -> M.Map Int [Int]
build_child_map_ m [] = m
build_child_map_ m (i:is) = if (parent i == Nothing) then
build_child_map_ m is
else
build_child_map_ (M.insertWith (++) (unwrap $ parent i) [internal_id i] m) is
sort_by_created_reverse :: [Item] -> [Item]
sort_by_created_reverse = sortBy created_sort_reverse
created_sort_reverse :: Item -> Item -> Ordering
created_sort_reverse a b = compare (created b) (created a)
In Erlang:
% @spec empty :: Model
empty() -> #model{}.
% @spec build_model :: [Item] -> Model
build_model([]) -> empty();
build_model(Is) ->
SortedIs = sort_by_created_reverse(Is),
Bid = dict:from_list([{I#item.internal_id, I} || I <- SortedIs]),
N = lists:max(dict:fetch_keys(Bid)),
#model{by_permatitle = dict:from_list([{X#item.permatitle, X} || X <- SortedIs]),
by_int_id = Bid,
child_map = build_child_map(SortedIs),
all_items = SortedIs,
next_id = N + 1}.
% @spec build_child_map :: [Item] -> M.Map Int [Int]
build_child_map(Is) -> build_child_map_(dict:from_list(lists:map(fun (X) -> {X#item.internal_id, []} end), Is), Is).
%% Constructed to take advantage of the input being in sorted order.
% @spec build_child_map_ :: M.Map Int [Int] -> [Item] -> M.Map Int [Int]
build_child_map_(D, []) -> D;
build_child_map_(D, [I|Is]) ->
case I#item.parent of
undefined ->
build_child_map_(D, Is);
P_Id ->
build_child_map_(dict:append(unwrap(P_Id), I#item.internal_id, D), Is)
end.
% @spec sort_by_created_reverse :: [Item] -> [Item]
sort_by_created_reverse(Is) -> lists:sort(fun created_sort_reverse/2, Is).
% @spec created_sort_reverse :: Item -> Item -> Ordering
created_sort_reverse(A, B) -> compare(B#item.created, A#item.created).
In Scala
object Entry {
def empty = new Model()
def build_model(items:List[Item]) = items match {
case Nil => empty
case _ =>
val sortedItems = sortByCreatedReverse(items)
val bid = Map() ++ sortedItems.map(item => (item.internalId -> item))
val n = bid.keys.toList.sort((A, B) => A > B).head // max
new Model(Map() ++ sortedItems.map(item => (item.permatitle -> item)),
bid,
buildChildMap(sortedItems),
sortedItems,
n + 1)
}
def buildChildMap(items:List[Item]) = buildChildMap_(Map() ++ items.map(item => (item.internalId -> Nil)), items)
private
def buildChildMap_(map:Map[Int, List[Int]], items:List[Item]) = {
for (item <- items if item.parent.isDefined; pid = item.parent.get) {
map + (pid -> (map.getOrElse(pid, Nil) + item.internalId))
}
map
}
def sortByCreatedReverse(items:List[Item]) = items.sort((A, B) => A.created before B.created)
}
I use ErlyBird for Erlang coding, and Scala for NetBeans for Scala coding. The experience seems that IDE is much aware of Scala, and I can get the typing a bit faster than writing Erlang code.
If you are not familiar with all these 3 languages, which one looks more understandable?