ตามมาจากโจทย์ใน forum ruby
โจทย์ ruby #21
ถ้าจะใช้ erlang เขียน มันจะลำบากขึ้นมาหน่อย
เพราะมีประเด็นที่มันต่างจาก imperative คือ
1. ตัวแปร assign ได้ครั้งเดียว ห้ามแก้ไข (immutable)
2. พวก list ก็เป็น immutable เหมือนกัน
ดังนั้น ประโยคแบบนี้ a = []; a << 1
ไม่มีใช้ใน erlang
3. ไม่มี global variable ให้ใช้
solution แรกสุด ใช้ pattern matching กับ tail-recursive
-module(part).
-export([part/2]).
part(L,Size) ->
part(L, [], Size).
part([], X, _) ->
lists:reverse(X);
part([H|T], [], Size) ->
part(T, [[H]], Size);
part([H|T], [H2|T2], Size) when length(H2) == Size ->
part(T, [[H]] ++ [H2|T2], Size);
part([H|T], [H2|T2], Size) ->
part(T, [H2 ++ [H]] ++ T2, Size).++ คือการ append array เข้าด้วยกัน
Note: การที่เราใช้ recursive มันมักจะจบลงด้วยการ reverse ค่าผลลัพท์สุดท้าย
แบบที่ 2 ปรับปรุงมาจากตัวแรก
เพิ่มให้มีตัวพัก เพื่อให้ดูง่ายขึ้น และไม่ต้องทำ reverse ด้วย
part2(L,Size) ->
part2(L, Size, [], []).
part2([], _, Temp, Result) ->
Result ++ [Temp];
part2([H|T], Size, [], Result) ->
part2(T, Size, [H], Result);
part2([H|T], Size, Temp, Result) when length(Temp) == Size ->
part2(T, Size, [H], Result ++ [Temp]);
part2([H|T], Size, Temp, Result) ->
part2(T, Size, Temp ++ [H], Result).แบบที่ 3 ลองหันไปใช้ higher order function บ้าง
part3([X|XS], Size) ->
lists:reverse(
lists:foldl(fun(Elm, [H|T]) ->
if length(H) == Size ->
[[Elm]] ++ [H|T];
true ->
[H ++ [Elm]] ++ T
end
end,
[[X]],
XS)).กระทู้เก่าๆ จะย้ายตามไปในภายหลัง ตอนนี้ปิดการโพสต์กระทู้ไว้ เหลือไว้เฉพาะอ้างอิงเท่านั้น
GeShi ไม่สนับสนุน Erlang ซะด้วย หาใน issue tracker ของ sourceforge ก็ไม่เห็น สงสัยจะได้ทำเองแล้วมั้ง
GeShi document section #4
mk: สงสัย… สมเป็นภาษานอกกระแสของนอกกระแส
อืม แบบที่สามแนวคิดคล้ายๆ ของอ.มะนาว
ลองเขียนเป็น ocaml มาใส่บ้าง พยายามแปล part3 (จริงๆผมคงมั่วออกนอกลู่นอกทางจาก part3 มาพอสมควร) น่าจะเป็นเพราะผมยังไม่แม่น ocaml แล้วก็มั่วเรื่อง functional ด้วย ออกมาแล้ว เละๆ ชอบกล T_T
open List;; let last x = (hd (rev x));; let cn21 a n = let rec f8 x b = if (length (last x)) > (n - 1) then f8 (append x [[]]) b else append (tl (rev x)) [(append (last x) [b])] in fold_left f8 [[]] a ;; let m = [1;2;3;4;5;6;7;8;9;10];; cn21 m 2;;last x นี่มันดูโหดๆอยู่นะ (ในแง่ที่ต้อง reverse list ทุกครั้ง)
ดูไปสักพัก rev เต็มไปหมดเลย :)
ดูๆแล้วเหมือน list ใน caml ดูมันจำกัดหลายอย่าง (อยากใช้ a[s..e] จะแย่) ใช้ Array แทนละกัน ไม่ใช้ rev ละ แฮ่ๆ
let last x = x.((Array.length x) - 1);; let cn21 a n = let rec sep x b = if Array.length (last x) > n - 1 then sep (Array.append x [|[||]|]) b else Array.append (Array.sub x 0 ((Array.length x) - 1)) [|(Array.append (last x) [|b|])|] in Array.fold_left sep [|[||]|] a ;; let m = [|1;2;3;4;5;6;7;8;9;10|];; cn21 m 2;;ใน caml list ประกาศโดย [1;2;3] พอเป็น Array ก็ใช้ [|1;2;3|] เป็นเครื่องหมายที่น่าทึ่งจริงๆ -_-'
ดูยากจัง...
ไม่ต้อง fold_left ได้มะ?
อ้อ ดูผิด พยายามเขียนให้เป็น part 3 นี่นา
เดี๋ยวผมพยายามเขียนแบบอื่นดูมั่งครับ ผมเลือกแบบ fold_left ก่อนเพราะมันไปเทียบกับ list comprehension ของ Python ได้ :-P
หลังจากที่เล่น ocaml แล้วใช้ inspector ไม่เป็น ก็เลยพยายามไปหา IDE ดีๆ มาใช้ :-P
ก็ได้ DrScheme มา ประกอบยังติดใจเรื่องการใช้ List อยู่ ก็เลยต้องเปลี่ยนมาเขียน scheme ด้วย -_-'
ผมว่าไม่ได้เหมาะกับมือใหม่ functional programming นะ
แต่มันเหมือนกับการเขียนโปรแกรมครั้งแรกเลยทีเดียว !!!
(ถ้าไม่นับ Logo อะนะ)
แล้วก็มี code มาอีก version ใช้ reverse น้อยกว่า ocaml #1 หน่อย
อ๊ะ ผมก็ใช้ drscheme อยู่นะแต่ไม่ยักรู้ว่าใช้เขียน ocaml ได้ด้วย
ขอบคุณครับ จะได้ลองเอา code ของวีร์ไปลอง run มั่ง
อ่านผิด ใจร้อนไปหน่อย
ของ ocaml มี camelia อะครับ แต่ก็ดูห่างชั้นจาก DrScheme
ที่บางมหาวิทยาลัย สอน Scheme เป็นภาษาแรกเลยอ่ะ
ประถมเรียน Logo เข้ามหาลัยเขียน Scheme ก็น่าจะดี แต่แหมมันไม่ real world lol
ลองเป็น scheme ด้วย
แต่ใช้วิธีเดียวกับ haskell หรือ ML ใน post โจทย์ ruby #21