ไปถึงบ้าน ฝนกำลังกระหน่ำ ก็เลยชวนลูกชายเบอร์สองออกไปเล่นน้ำฝนกัน (คนแรกไม่ชวน เพราะว่าพ่อพาขี่จักรยานตากฝนไปโรงเรียนบ่อยแล้ว)

เล่นได้พักเดียว ฟ้าผ่าเปรี้ยง เจ้าลูกชายวิ่งแนบเข้าบ้าน
Javaเร็วส์, Javascript, Erlang, Python, Ruby, Clojure, Groovy, เลี้ยงลูก, วาดภาพ
-module(blog_post, [Id, Title, Text, AuthorId]).
-compile(export_all).
-belongs_to(author).
-module(author, [Id, Name]).
-compile(export_all).
-has_many(blog_posts).
FakeAuthor = (author:new(id, "YOUR NAME")):save(),
BlogPost = blog_post:new(id,
"BLOG TITLE",
"BLOG CONTENT",
FakeAuthor:id()),
SavedBlogPost = BlogPost:save(),
-module(p).
-export([start/0, say_something/2]).
say_something(What, 0) ->
done;
say_something(What, Times) ->
io:format("~p~n", [What]),
say_something(What, Times - 1).
start() ->
spawn(tut14, say_something, [hello, 3]),
spawn(tut14, say_something, [goodbye, 3]).
{ok,[{attribute,1,file,{"p.erl",1}},
{attribute,1,module,p},
{attribute,2,export,[{start,0},{say_something,2}]},
{function,3,say_something,2,
[{clause,3,
[{var,3,'What'},{integer,3,0}],
[],
[{atom,4,done}]},
{clause,5,
[{var,5,'What'},{var,5,'Times'}],
[],
[{call,6,
{remote,6,{atom,6,io},{atom,6,format}},
[{string,6,"~p~n"},{cons,6,{var,...},{...}}]},
{call,7,
{atom,7,say_something},
[{var,7,'What'},{op,7,'-',...}]}]}]},
{function,8,start,0,
[{clause,8,[],[],
[{call,9,
{atom,9,spawn},
[{atom,9,tut14},
{atom,9,say_something},
{cons,9,{...},...}]},
{call,10,
{atom,10,spawn},
[{atom,10,tut14},
{atom,10,say_something},
{cons,10,...}]}]}]},
{eof,11}]}
parameter_getter_forms(Parameters) ->
lists:map(fun(P) ->
erl_syntax:add_precomments([erl_syntax:comment(
[lists:concat(["% @spec ", parameter_to_colname(P), "() -> ", P]),
lists:concat(["% @doc Returns the value of `", P, "'"])])],
erl_syntax:function(
erl_syntax:atom(parameter_to_colname(P)),
[erl_syntax:clause([], none, [erl_syntax:variable(P)])]))
end, Parameters).
parameter_setter_forms(ModuleName, Parameters) ->
lists:map(
fun(P) ->
erl_syntax:add_precomments([erl_syntax:comment(
[
lists:concat(["% @spec ", parameter_to_colname(P), "( ", P, "::",
case lists:suffix("Time", atom_to_list(P)) of
true -> "tuple()";
false -> "string()"
end, " ) -> ", inflector:camelize(atom_to_list(ModuleName))]),
lists:concat(["% @doc Set the value of `", P, "'."])])],
erl_syntax:function(
erl_syntax:atom(parameter_to_colname(P)),
[erl_syntax:clause([erl_syntax:variable("NewValue")], none,
[
erl_syntax:application(
erl_syntax:atom(ModuleName),
erl_syntax:atom(new),
lists:map(
fun
(Param) when Param =:= P ->
erl_syntax:variable("NewValue");
(Other) ->
erl_syntax:variable(Other)
end, Parameters))
])]))
end, Parameters).
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
[a]
จะเห็นว่า type [a]
มันสามารถมองเป็น m a
ได้ (เพราะ type constructor มันมี free variable 1 ตัวเหมือนกัน) ฉนั้นเราลองมา implement ให้ List เป็น Monad กันa -> m a
ฉนั้นกรณีของ List, คำสั่ง return 4
ก็ควรได้ค่า [4]
ออกมาinstance Monad [] where
return x = [x]
>>=
นิยามของ type มันคือ m a -> (a -> m b) -> m b
m a
ให้เป็น [a]
จะได้ [a] -> (a -> [b]) -> [b]
จะเห็นว่า definition มันไกล้เคียงกับ map function ที่มี type เป็น [a] -> (a -> b) -> [b]
ดังนั้นเราสามารถ implement >>=
โดยใช้ map และ concat instance Monad [] where
return x = [x]
xs >>= f = concat (map f xs)
ถ้าให้ list ของ [1..10] มาให้หาตัวเลข 2 ตัวที่ผลคูณมีค่า = 16
guard True xs = xs
guard False xs = []
solve = do
x <- [1..10]
y <- [x..10]
guard (x * y == 16) (return (x,y))
[(x,y) | x <- [1..10], y <- [x..10], x * y == 16]
flat1 :: Store a -> a
flat1 (E a) = return a
flat1 (S xs) = xs >>= flat1
Your (flat xs) on a list of stores becomes my (xs >>= flat1), systematically lifting the operation on a single store to lists of them and concatenating the results. The return operation makes a singleton from an element. This way of working with lists by singleton and concatenation is exactly the monadic structure which goes with the list type, so you get it from the library by choosing to work with list types. In Haskell, when you choose a typed representation for data, you are not only choosing a way of containing the data but also a way to structure the computations you can express on that data