tag:blogger.com,1999:blog-62657062508879130302024-03-12T17:16:49.244-07:00Read . Write . SleepJanhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.comBlogger49125tag:blogger.com,1999:blog-6265706250887913030.post-79814387470527859162012-01-02T17:33:00.000-08:002012-01-02T18:38:49.077-08:00One Week on Node<span style="font-family: Georgia, serif; font-size: 100%; font-variant: normal; font-weight: normal; line-height: normal; font-style: italic; ">Just want to write down some feelings on a small nodejs project I worked on last week.</span><br /><br />* Fast. Everything is fast (attribute to Google v8 and node guys). REPL opened in a twinkle, tests finish before I grab my teacup. No more waiting for "warm up".<div><br /></div><div>* NPM. It's so good. I like the idea to install all dependencies locally in project directory. Mentally, dependencies are part of your application, it make sense for them to live together. Physically, put dependencies in project directory will solve dependency conflicts between applications naturally; besides that, it enables you to jump into deeper (library) code more easily, if you use a decent editor like vim or textmate, because all files are in one place so a simple search will find them all.</div><div><br /></div><div>* Library boom. Maybe a requirement to success, but it goes a little wild. In some area like testing, tons of immature tools are there, no one can tell a best practice. I have to examine all these tools to find a best fit to my project. I really miss something like rails guide or ruby-toolbox.com here.</div><div><br /></div><div>* Asynchronization is still hard. It's hard for the same reason GOTO statement is hard, or lazy evaluation is hard. It messes up my tiny little brain easily by disrupts the execution order. The weird exception backtrace only make the situation worse (however this should be fixable). The little piece of asynchronous code is like virus, it gradually infects the rest parts of your application (IO monad: ah?). The co-routine tricks/tools people used to dress asynchronous code up to synchronous code still looks awkward (and here's another area suffers the library boom problem). I will be very careful if someone propose to write an entire application in node, it would be better if I can restrict asynchronous code on a small land. I bet node is better in polyglot paradigm, e.g. node as my ajax push server, rails to power most web pages.</div><div><br /></div><div><b>Node is great! Be careful with asynchronous calls!</b></div>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-42286501120312851522011-09-26T03:32:00.000-07:002011-09-26T04:04:52.697-07:00Running Rails 3.1.1 on Heroku<a href="http://devcenter.heroku.com/articles/rails31_heroku_cedar#troubleshooting">Heroku officially supports rails 3.1.1 on their Cedar stack now</a>, unfortunately, you may still fail on deploy. The trouble maker is the assets:precompile rake task in rails 3.1. Heroku runs 'rake assets:precompile' for you when deploy, at a time many application dependencies, e.g. database server, redis, are NOT ready, so if there's any database/redis/any-other-not-ready-dependency use in your rails initialization process, assets:precompile will fail.<br /><br /><div>The tricky thing is, even you know the underlying theory, it's hard to find the exact place caused the problem, because heroku deployment do not use '--trace' flag when running precompile task, the limited error output is almost useless; and rails initialization process walks through so many files it's stupid to check them one by one. </div><div><br /></div><div>For example, this is the error I got today when I deploy to heroku:</div><pre><code><br />rake aborted!<br />bad URI(is not URI?):<br /></code></pre><br />Can you spot the broken code with so few information? I can't ... Fortunately, we can ask rake to give detail error stack without passing it '--trace' option, by adding this line in your Rakefile:<br /><pre><code><br />Rake.application.options.trace = true if %w(staging production).include?(Rails.env)<br /></code></pre><br />Then another problem pops up, I now found the broken code, how to fix it? Since the broken code uses something that is not ready when assets:precompile task running, an easy way would be:<br /><pre><code><br /># in Rakefile<br />if %w(staging production).include? Rails.env<br />$heroku_deploying = true if File.basename($0) == 'rake' && ARGV.include?('assets:precompile')<br />end<br /><br /># in some initializers:<br /># reference to UsersController will trigger operation on database<br />provider :identity, :fields => [:name, :email, :nickname], :on_failed_registration => UsersController.action(:new) unless $heroku_deploying<br /></code></pre><br />With this duct tape kind fix, you may have $heroku_deploying scattered in your code .. it's ugly but works. Let me know if you have better idea :-)<br /></any>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-18540406339618754082011-06-17T01:47:00.000-07:002011-06-17T02:10:11.571-07:00[ANN] Rubytest.vim 1.1.0 Released!There're two major changes in this release:<div><br /></div><div>* Remember last run: <leader><leader>l to run last run test (thanks John Weir!)</leader></div><div>* Default support to rspec2. You need to customize g:rubytest_cmd_spec to work with rspec 1.*</div><div><br /></div><div>Download [1][2] and copy/overwrite to install/upgrade!</div><div><br /></div><div>1. <a href="http://www.vim.org/scripts/script.php?script_id=2612">http://www.vim.org/scripts/script.php?script_id=2612</a></div><div>2. <a href="http://github.com/janx/vim-rubytest/tree/master">http://github.com/janx/vim-rubytest/tree/master</a></div>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-7111528102092304542011-05-30T21:17:00.000-07:002011-05-30T21:20:45.330-07:00ZJU the Champions of ACM-ICPC World Finals 2011!<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqZF8uUu1rg0XHWdgK1JRXTY4TkAh31rV2nkNUD8VCgy0xqra99j9dDrjpFEtSPEk3Rh92-l0JHuO0tyAcNOVRgn9FWZl2e9Nc1MRM9L-Hho7amCl3h9LyjEVLDL9Idem6ddgUDmaKl6A/s1600/ugmbbc_103252786400877_small.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"><img style="cursor:pointer; cursor:hand;width: 320px; height: 214px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqZF8uUu1rg0XHWdgK1JRXTY4TkAh31rV2nkNUD8VCgy0xqra99j9dDrjpFEtSPEk3Rh92-l0JHuO0tyAcNOVRgn9FWZl2e9Nc1MRM9L-Hho7amCl3h9LyjEVLDL9Idem6ddgUDmaKl6A/s320/ugmbbc_103252786400877_small.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5612730158489515314" /></a><div><br />Finally, finally, congratulations ~ <a href="https://cm.baylor.edu/ICPCWiki/Wiki.jsp?page=Results%20World%20Finals%202011">Rankings</a></div><div><div><br /></div></div>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-47638995330576303022011-01-26T21:31:00.000-08:002011-01-26T21:49:56.891-08:00Angry TerminalLast night I got the idea that using different colors in shell prompt to tell the user about the result of last command executed, e.g. red for failed execution and green for success.<br /><br />It's really easy to do that in <a href="http://www.zsh.org/">the ultimate shell</a>, all I need is a function and a prompt using it:<br /><pre><code><br />function prompt_base_color() {<br /> if [[ $? == "0" ]]; then<br /> echo $PR_GREEN<br /> else<br /> echo "$PR_RED"<br /> fi<br />}<br /><br />PROMPT='$PR_SET_CHARSET$PR_STITLE${(e)PR_TITLEBAR}$(prompt_base_color)%D{%H:%M} $PR_GREEN%~ $PR_RED$(git_prompt_info)$PR_NO_COLOUR'<br /></code></pre>It make your terminal look like this:<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgryN6TrZPGvqQlsXcw2PGQQGipZDewNENcok0iultymOdVb0nZnl8d8ltzTdOQaKfSvY5GDwfewzKwrUiv3W_PGcC2M0d8JeudU__gxu9kJDky1K9wG4Fv_JG5ozBLtD32Wdv5Ijbw_nQ/s1600/screenshot_022.png"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgryN6TrZPGvqQlsXcw2PGQQGipZDewNENcok0iultymOdVb0nZnl8d8ltzTdOQaKfSvY5GDwfewzKwrUiv3W_PGcC2M0d8JeudU__gxu9kJDky1K9wG4Fv_JG5ozBLtD32Wdv5Ijbw_nQ/s320/screenshot_022.png" alt="" id="BLOGGER_PHOTO_ID_5566737398886056610" border="0" /></a><br /><br />Then I realized I can go one step further to help terminal express her feeling, I always feel she is angry with me.<br /><br />So I changed the function a bit, like this:<br /><pre><code><br />function prompt_base_color() {<br /> if [[ $? == "0" ]]; then<br /> echo $PR_GREEN<br /> else<br /> txt=`cat ~/.zsh/my_ass.txt`<br /> echo "$txt\n$PR_RED"<br /> fi<br />}<br /></code></pre>And put the feeling in a file by `cowsay My ASS > ~/.zsh/my_ass.txt`.<br /><br />Now Miss Terminal can tell me what she thinks when I do something wrong!<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMmR8d_7kWK9IXmqj51yMIHB_xB8M7c0xIbfh9UosDVHAvOAeCO_DjWnIYgWEpMIiIKyKSGxnmeWukJcZfo0Q0YpygpKL7HOCC837YgT16gJ4c_Ada6twUNrzsW7V65E97IFeSWVMmkxM/s1600/screenshot_023.png"><img style="cursor: pointer; width: 320px; height: 149px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMmR8d_7kWK9IXmqj51yMIHB_xB8M7c0xIbfh9UosDVHAvOAeCO_DjWnIYgWEpMIiIKyKSGxnmeWukJcZfo0Q0YpygpKL7HOCC837YgT16gJ4c_Ada6twUNrzsW7V65E97IFeSWVMmkxM/s320/screenshot_023.png" alt="" id="BLOGGER_PHOTO_ID_5566737960482402450" border="0" /></a>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-31035169151326015662010-11-26T09:32:00.000-08:002010-11-26T09:44:59.506-08:00QorCMS previewQor is the admin tool <a href="http://theplant.jp">we</a> build for rails. It's not public released yet but already used by some of our clients. It's like the Django one but only better!<br /><br /><iframe src="http://player.vimeo.com/video/17209929" width="400" height="225" frameborder="0"></iframe><p><a href="http://vimeo.com/17209929">Qor Enterprise CMS Demo</a> from <a href="http://vimeo.com/user5308918">Felix Sun</a> on <a href="http://vimeo.com">Vimeo</a>.</p>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-78148262264311251932010-11-04T23:35:00.000-07:002010-11-04T23:56:28.701-07:00Compiling Google mod_pagespeed on ArchlinuxGoogle released its awesome apache module <a href="http://www.modpagespeed.com/">mod</a>_<a href="http://code.google.com/p/modpagespeed/">pagespeed</a> recently. Unfortunately only .deb/.rpm packages are provided officially. For arch user, we have to compile it by ourselves.<br /><br />Based on google's howto, we need <a href="http://www.chromium.org/developers/how-tos/depottools">depot_tools</a> to compile mod_pagespeed. There is an aur package <a href="http://aur.archlinux.org/packages.php?ID=25861">depot_tools-svn</a>, but seems not work now because arch switched to python 3.<br /><br />So I downloaded depot_tools myself and put it in my ~/scripts/depot_tools.<br /><br /><blockquote> mkdir -p ~/scripts<br /> cd ~/scripts<br /> svn co http://src.chromium.org/svn/trunk/tools/depot_tools</blockquote><br /><br />To make depot_tools work, you need to switch to python2:<br /><br /><blockquote>sudo rm /usr/bin/python<br />sudo ln -s /usr/bin/python2 /usr/bin/python<br />sudo rm /usr/bin/python-config<br />sudo ln -s /usr/bin/python2-config /usr/bin/python-config</blockquote><br /><br />Next step we download mod_pagespeed source code use depot_tools:<br /><br /><blockquote> mkdir ~/mod_pagespeed # any directory is fine<br /> cd ~/mod_pagespeed<br /> gclient config http://modpagespeed.googlecode.com/svn/trunk/src<br /> gclient sync --force # this will download all source code</blockquote><br /><br />You're ready to compile now.<br /><br /><blockquote> cd ~/mod_pagespeed/src<br /> make BUILDTYPE=Release # BUILDTYPE defaults to 'Debug'<br /></blockquote><br /><br />I got an error when I compile it on my box:<br /><br /><blockquote>In file included from /usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.1/../../../../include/c++/4.5.1/utility:71:0,<br /> from /usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.1/../../../../include/c++/4.5.1/algorithm:61,<br /> from ./net/instaweb/util/fetcher_test.h:24,<br /> from ./net/instaweb/util/cache_fetcher_test.h:27,<br /> from net/instaweb/util/cache_fetcher_test.cc:19:<br />...<br />/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.1/../../../../include/c++/4.5.1/bits/stl_map.h:87:5: instantiated from here<br />/usr/lib/gcc/x86_64-unknown-linux-gnu/4.5.1/../../../../include/c++/4.5.1/bits/stl_pair.h:77:11: error: ?std::pair<_t1,>::second? has incomplete type<br />./net/instaweb/util/public/cache_interface.h:28:7: error: forward declaration of ?struct net_instaweb::SharedString?<br /></blockquote><br /><br />After digging a while, I made this patch to fix the error:<br /><br /><blockquote>Index: net/instaweb/util/public/cache_interface.h<br />===================================================================<br />--- net/instaweb/util/public/cache_interface.h (revision 137)<br />+++ net/instaweb/util/public/cache_interface.h (working copy)<br />@@ -21,6 +21,7 @@<br /><br />#include <string><br />#include "net/instaweb/util/public/string_util.h"<br />+#include "net/instaweb/util/public/shared_string.h"<br /><br />namespace net_instaweb {</blockquote><br /><br />ps: I also deployed mod_pagespeed to our centos staging server, the whole process is very smooth. The result is also very impressive: gzip, cache-control, inline assets, etc. etc. all suddenly work like a charm. The only problem is with extend_cache filter: it modified asset name correctly, but when brower send request to those assets, the server reponds with 404 error. I have to disable rewrite_javascript and extend_cache filter to make our sites work correctly:<br /><br /> <blockquote> ModPagespeedDisableFilters rewrite_javascript<br /> ModPagespeedDisableFilters extend_cache</blockquote>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com3tag:blogger.com,1999:blog-6265706250887913030.post-24042943251254474802010-10-26T03:21:00.000-07:002010-10-26T04:08:10.588-07:00On Vim againThere's only 10 kinds of people, those who use Vim, and those who use Emacs.<br /><br />Two months ago I don't know whether I'm wrong on choosing Vim as my editor, now I know I made a right decision, one of those few right decisions in my life.<br /><br />Emacs can do everything, except editing texts, everyone knows it. But I didn't expect that I can't simply *copy a line* before I learned to use it. I can copy a line by press y twice in Vim by one finger while the other hand is filling my mouth with cookies; I need to move the cursor to the beginning of a line, press C-S-e, then press M-w to copy the damn line.<br /><br />Of course I can write a macro and map the copy-line macro to my favorite keys. Yes, I can also write a text editor myself. Those two doesn't have much differences, no?<br /><br />Be serious: I really wrote a macro to do that, the problem is when I tried to map it to some key I failed - there's no reasonable key combination left for me to use. C-y? that's for yank, C-c? that's a common prefix, etc. etc. I don't want to match copy-line to something like C-c C-t C-y, that just won't save my time and stupid.<br /><br />Luckily Emacs do leave some key combination possibilities for me, so I can quick access find file/buffer functions. I'd say <a href="http://www.emacswiki.org/emacs/InteractivelyDoThings">ido</a> is really awesome, that's what I miss when I switch back to Vim. Vim lacks a decent file navigator. <a href="http://www.vim.org/scripts/script.php?script_id=1984">FuzzyFinder</a> is cool, but it's turtle slow on large project.<br /><br />I also miss ruby-test-mode, which can do exactly the same thing but faster than my little <a href="http://www.vim.org/scripts/script.php?script_id=2612">rubytest.vim</a>.<br /><br />Emacs follows totally different philosophy than Vim: Emacs included everything in itself, while Vim leave everything but editing to others. An example is <a href="http://www.gnu.org/software/tramp/">Tramp</a>. Tramp is really cool because you can prefix the file name with 'su::/' or 'su:root@hostfoo' when you want to edit a file you have no privileges or on a remote server, it's not convenient to do the same thing in Vim. But I found myself more like to open a terminal and sudo vim /etc/hosts. (btw. emacs in console sucks.) I believe Emacs fits certain people, people who like to do everything in one place.<br /><br />Sometimes I think Emacs is for people who're using poor window manager. Because if you're using something like Gnom's default metacity, it's hard to create a new console, do something there while reading stuff in your text editor, then switch back to your editor. In short, most window managers doesn't allow you to manipulate layout between your editor and task windows easily. But if you're using <a href="http://en.wikipedia.org/wiki/Tiling_window_manager">tiling window manager</a> like <a href="http://xmonad.org/">XMonad</a>, I think Vim is the best fit because you can always do something in a new window easily while looking at your editor.<br /><br />Emacs is cool. I just like Vim more.<br /><br /><a href="http://imgs.xkcd.com/comics/real_programmers.png"><img src="http://imgs.xkcd.com/comics/real_programmers.png" width="420" /></a>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com2tag:blogger.com,1999:blog-6265706250887913030.post-15672710897728177882010-08-25T21:38:00.000-07:002010-08-25T22:04:56.234-07:00Find missing git refI was a fool this morning: I rsynced old source code from my macbook to my new thinkpad w510. I have been working on the new thinkpad since Tuesday, without a push to github (ye, fool again), so all recent works exist only on thinkpad. After the rsync, I found the last commit in my git repo is committed 2 days ago ..<br /><br />After a period of a mix of jump/cry/smoke/hit walls with my head/... I calmed down. Git saves any new file after you commit, it also save the tree and commit as object files, then it modify the ref to point to the new commit file. Rsync only ruined my refs, overwrite them to point to the old commit file, but the new source file, tree, commit should be still there on my dear harddisk. If I can find the last commit file of yesterday, then modify the ref to that commit manually, I may get all my changes back!<br /><br />First I need to list all object files related to the yesterday's last commit. A while later I find them with:<br /><pre><code><br />cd .git<br />find . -newer <the newest file in current corrupted repo> -type f | xargs ls -l | grep object | grep "Aug 25 19:09" | awk '{print $9}'<br /></code></pre><br />The result is like this:<br /><pre><code><br />./objects/0d/34526c4149e4c89c436a058c66d1b69850dcea<br />./objects/0d/3d1caf38f65e6b7f2b7b693d721b66c6cda45d<br />./objects/0e/e7efbe5eeb7a320c09046011e9fc5e10e51a88<br />./objects/36/d3fdab703e5e080bf63bb76c069fa51a456a24<br />./objects/59/3371c18e1657d786265b46deb747f3d8cc8d00<br />./objects/76/3da4c776fae22d4cbee789703790f81fcfaed5<br />./objects/a0/9a140235ce52747157a6b199c99a464a5545a4<br />./objects/b1/a080cda86596501ee5bd88181c89fae1d5f07d<br />./objects/bb/a640a7830fafa3d9ae352a2b060df600a4d5e7<br />./objects/cb/ddce9d6079a720e13492c4ea055fb61b6e908b<br />./objects/e3/5a4ba7d374dd96f70a763d128ac849be173b86<br /></code></pre><br />The next step is to check the contents and find the commit in these object files. I tried with `git cat-file` first, but it just report "fatal: Not a valid object name 3fc43a817252e031f6d0c387930539b4c613bc" again and again, because the new object is not in the old repo really.<br /><br />After a google around I found a one-liner python script to inspect the content of object file, that's what I need exactly:<br /><pre><code><br />python -c 'import sys,zlib; sys.stdout.write(zlib.decompress(open(sys.argv[1]).read()))' <path-to-object-file><br /></code></pre><br />Next is easy: I just checked each object file manually, and found the lovely commit object file at the 9th try:<br /><pre><code><br />commit 232tree b1a080cda86596501ee5bd88181c89fae1d5f07d<br />parent 09f4a0cd1374d848bffffba6c02fa6830aea587a<br />author Jan <j@xxxxxxxx.xx> 1282734563 +0800<br />committer Jan <j@xxxxxxxx.xx> 1282734563 +0800<br /></code></pre><br />The file name of the commit is ./objects/bb/a640a7830fafa3d9ae352a2b060df600a4d5e7, so I just modified the content of refs/head/branch-name to bba640a7830fafa3d9ae352a2b060df600a4d5e7.<br /><br />The last step is go back to the repo, clean the repo with 'git reset --hard' because the files are still in old revision. Then everything just come back!Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-9814043863023123032010-07-01T01:39:00.000-07:002010-07-01T02:03:12.335-07:00Universal Quantification, Bound and Existential QuantificationUniversal quantification is usually not very useful. Inside the body of a universal quantified function, what you know about the argument is very general, because the argument can be *any* type. Suppose you're writing a function with type *->Int, what do you think the function can do? The only implementation I can think of is a constant function:<br /><br />(pseudo codes)<br /><br /><pre><code><br /> f1 :: [forall a] a -> Int<br /> f1 x = 1<br /></code></pre><br /><br />In contrast, existential quantified functions are very useful, because there're always *some* types can do certain things. Use the same example:<br /><br /><pre><code><br /> f2 :: [exist a] a -> Int<br /> f2 x = length x<br /></code></pre><br /><br />I can do nearly anything inside f2, because there's always some x will satify the operations applied on them.<br /><br />You should notice that only functions or Bottom can have universal quantified type.<br /><br />Bound helps universal quantification a lot. When you give a bound to universal quantification, you give it extra informations.Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-9713542601299526112010-05-06T01:57:00.000-07:002010-05-06T02:11:27.402-07:00Ruby 1.8.7 and openssl 1.0.0Archlinux upgrade openssl from 0.9.8 to 1.0.0 recently, which caused a big headache for me: all ruby distributions, except the latest ruby source code in svn, failed to compile with the new openssl, e.g. (compile error of 1.8.7):<div><br /></div><div></div><blockquote><div>ossl_ssl.c: In function ?ossl_sslctx_get_ciphers?:</div><div>ossl_ssl.c:626:19: error: ?STACK? undeclared (first use in this function)</div><div>ossl_ssl.c:626:19: note: each undeclared identifier is reported only once for each function it appears in</div><div>ossl_ssl.c:626:25: error: expected expression before ?)? token</div><div>ossl_ssl.c:629:47: error: expected expression before ?)? token</div><div>ossl_ssl.c:629:47: error: too few arguments to function ?sk_value?</div><div>/usr/include/openssl/stack.h:80:7: note: declared here</div><div>ossl_ssl.c: In function ?ossl_ssl_get_peer_cert_chain?:</div><div>ossl_ssl.c:1199:5: warning: passing argument 1 of ?sk_num? from incompatible pointer type</div><div>/usr/include/openssl/stack.h:79:5: note: expected ?const struct _STACK *? but argument is of type ?struct stack_st_X509 *?</div><div>ossl_ssl.c:1202:2: warning: passing argument 1 of ?sk_value? from incompatible pointer type</div><div>/usr/include/openssl/stack.h:80:7: note: expected ?const struct _STACK *? but argument is of type ?struct stack_st_X509 *?</div><div>ossl_ssl.c: In function ?ossl_ssl_get_cipher?:</div><div>ossl_ssl.c:1224:12: warning: assignment discards qualifiers from pointer target type</div><div>make[1]: *** [ossl_ssl.o] Error 1</div><div>make: *** [all] Error 1</div><div><br /></div><div></div></blockquote><div><a href="http://gist.github.com/391947">Here's a patch for 1.8.7</a>, it's a modified version of <a href="http://cvs.fedoraproject.org/viewvc/rpms/ruby/F-12/ruby-openssl-1.0.patch?view=log">this</a>. Copy and save it as openssl.patch in 1.8.7 source directory, run 'patch -p0 < openssl.patch' and recompile, there should be no errors anymore.</div>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com7tag:blogger.com,1999:blog-6265706250887913030.post-24743840588008182022010-03-25T00:38:00.000-07:002010-03-25T00:45:29.831-07:00GoF's refactoring draft of the old 23 design patterns* Interpreter and Flyweight should be moved into a separate category that we referred to as "Other/Compound" since they really are different beasts than the other patterns. Factory Method would be generalized to Factory.<br /><br />* The categories are: Core, Creational, Peripheral and Other. The intent here is to emphasize the important patterns and to separate them from the less frequently used ones.<br /><br />* The new members are: Null Object, Type Object, Dependency Injection, and Extension Object/Interface (see "Extension Object" in Pattern Languages of Program Design 3, Addison- Wesley, 1997).<br /><br />* These were the categories:<br /> + Core: Composite, Strategy, State, Command, Iterator, Proxy, Template Method, Facade<br /> + Creational: Factory, Prototype, Builder, Dependency Injection<br /> + Peripheral: Abstract Factory, Visitor, Decorator, Mediator, Type Object, Null Object, Extension Object<br /> + Other: Flyweight, Interpreter<br /><br /><a href="http://www.informit.com/articles/article.aspx?p=1404056">via</a>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-6416069429721464332010-03-10T20:49:00.000-08:002010-03-10T20:54:38.232-08:00[ANN] Rubytest.vim 1.0.0 ReleasedRubytest.vim is a vim (http://www.vim.org) plugin, which helps you to run tests/specs/features in vim, in order to accelerate your red-green development circle.<br /><br />Within this realease, rubytest.vim supports almost all popular TDD/BDD frameworks in ruby community: testunit, rspec, shoulda, cucumber ...<br /><br />Happy hacking!<br /><br />Changelog<br />---------<br /><br />* Support cucumber features<br />* Support rspec drb mode<br />* Serveral bug fixes<br /><br />Get it here: <a href="http://www.vim.org/scripts/script.php?script_id=2612">http://www.vim.org/scripts/script.php?script_id=2612</a>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-86133280313986323162010-02-28T18:17:00.000-08:002010-03-01T00:35:19.640-08:00TokyoTyrant vs MongoDB vs CouchDB, simple benchmarksJeffery Zhao published <a href="http://www.cnblogs.com/JeffreyZhao/archive/2010/02/24/mongodb-tokyo-tyrant-benchmark-1-basic-cru-operations.html">a simple benchmark</a> of 2 '<a href="http://en.wikipedia.org/wiki/Nosql">NoSQL</a>' databases recently. In that article only basic CRU operations are compared. On macbook unibody+osx, which is the platform Jeff use, <a href="http://en.wikipedia.org/wiki/MongoDB">MongoDB</a> got slightly better scores than <a href="http://1978th.net/tokyotyrant/">TokyoTyrant</a> on almost every aspect.<br /><br />We're very interested in <a href="http://couchdb.apache.org/">CouchDB</a> these days, so I <a href="http://github.com/janx/mdb-tt-benchmark">cloned Jeff's benchmark suite, added scripts for CouchDB</a>, and ran the benchmark on my platform, macbook unibody+archlinux again. However the result is really interesting - it's totally the opposite - TokyoTyrant is much more faster than MongoDB on my box.<br /><br />Results:<br /><iframe src="http://spreadsheets.google.com/pub?key=tkGpGEw6D79Ppm3uoEzx-EA&output=html&widget=true" frameborder="0" height="220" width="420"></iframe><br /><br />CouchDB is really slow compared to TT or MongoDB, so I just give up it after serveral round.<br /><br />The only difference between Jeff's and mine platform seems operating system: he use OSX while I use linux. I'm not sure whether this is the reason we get different results, or because TT is well optimized by gcc on linux?<br /><br />Try it yourself: <a href="http://github.com/janx/mdb-tt-benchmark">Simple NoSQL Bench</a> (The suite is written in Ruby)<br /><br /><span style="font-style: italic;">update: After changed from Net::HTTP to Curb, couchdb benchmarks improved about 1/3. Config couchdb [uuids] algorithm to sequential (in default.ini) has no effect on result. All 3 drivers connect to database through network, but only couchdb use http protocol, this is a bottleneck, or, trade off.</span>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com7tag:blogger.com,1999:blog-6265706250887913030.post-22788842823542234352010-02-28T17:49:00.000-08:002010-02-28T17:53:06.929-08:00Not Invented Here'In programming, it is also common to refer to the NIH Syndrome as the tendency towards reinventing the wheel (reimplementing something that is already available) based on the flawed belief that in-house developments are inherently better suited, more secure or more controlled than existing implementations. This argument is accepted as flawed because wide usage is much more likely to uncover any existing defects than reimplementation. Even more, peer review of source code in the case of a Free Software or Open Source alternative tends to follow Linus' Law: "given enough eyeballs, all bugs are shallow"'<br /><br /><a href="http://en.wikipedia.org/wiki/NIH_syndrome">Not Invented Here</a>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-50244033751552366292010-02-23T19:12:00.000-08:002010-02-23T19:19:09.716-08:00Patent System<a href="http://news.slashdot.org/comments.pl?sid=1560168&cid=31244084">HungryHobo's comment</a> on /.:<br /><br />Without patents:<br /><br />1: I write some nice software and sell it.<br />2a: I make a little money, not enough to quit my day job.<br />2b: I don't make money, all I've lost is time.<br /><br />With patents:<br /><br />1: I try to research previous patents, they're almost unreadable..... I have no money to hire a patent lawyer(barrier to entry one)... so I can't be certain if my idea has already been patented.<br />2a: I stop for fear of infringing on someones patent and being sued into the ground.(barrier to entry 2)<br />2b: I keep going and write my app... it might be infringing but I don't think it is....<br />3a: I make a little money.<br />3b: I make no money.<br />4: Someone sues me.<br />5a: It is infringing- well they pull out records that yes I did view their patent in the course of my research in step 1 and obviously stole their idea. They get tripple damages I lose my house. (barrier to entry 3)<br />5b: It is not infringing - so what. I don't have the money for a good lawyer, they win I lose my house.(barrier to entry 4)<br />5c: It is not infringing - by some miracle I win.... I'm still left with a pile of legal bills and I lose my house.(barrier to entry 5)<br /><br />In theory the patent system could help me by letting me be just like the guys who sue in the above but I don't have the thousands of dollars it takes to get a patent through nor the time.Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-58312653713786991362010-01-05T19:54:00.000-08:002010-01-05T20:56:22.110-08:00Random thoughts on AII'm always pessimistic about AI.<br /><br />Our current computation model is deterministic. Do you remember how Dijkstra 'proves' goto statement is harmful? He use one (or serveral) natural number(s) to represent the state of your process. We can map serveral natural numbers to a rational number, so in fact we can represent any state of any process as a rational number. A Turing Machine program has only two possible results: either terminate in finite time, like finite numbers, or trap in a infinite loop, like repeating decimals. Lambda calculus is proven to be a equivalence of Turing Machine.<br /><br />But our brain is non-deterministic. I have a strong feeling that you can't describe the state of brain by a rational number, but a irrational number. You can predict what's the n-th digit of a rational number, while you can't predict the n-th digit of a irrational number, you won't know it until your computation reached that point.<br /><br />The problem is that rational numbers live in a closure. You can't get an irrational number by applying basic arithmetic on rational number. If we can't get irrational number from rational number, can we get a brain from Turing machine? Maybe, if we find which state does PI represent of in a program.<br /><br />The foundation of our world is non-deterministic. It seems easy to build deterministic base on non-deterministic, but hard in reverse. So I guess it will be hard to build a brain base on Turing Machine. Fortunately we have a new hope at our age, named Quantum Computing, which is based on non-deterministic mechanism. I know little about how it works, but it looks totally different from old fashion computation models.Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com1tag:blogger.com,1999:blog-6265706250887913030.post-90378167707315362922009-11-26T23:03:00.000-08:002009-11-26T23:38:18.466-08:00CS Education"Programming is usually taught by examples. Experience shows that the success of a programming course critically depends on the choice of these examples. Unfortunately, they are too often selected with the prime intent to demonstrate what a computer can do. Instead, a main criterion for selection should be their suitability to exhibit certain widely applicable techniques. Furthermore, examples of programs are commonly presented as finished "products" followed by explanations of their purpose and their linguistic details. But active programming consists of the design of new programs, rather than contemplation of old programs. As a consequence of these teaching methods, the student obtains the impression that programming consists mainly of mastering a language (with all the peculiarities and intricacies so abundant in modern PL's) and relying on one's intuition to somehow transform ideas into finished programs. Clearly, programming courses should teach methods of design and construction, and the selected examples should be such that a gradual development can be nicely demonstrated. "<br /><br />- <a href="http://sunnyday.mit.edu/16.355/wirth-refinement.html">"Program Development by Stepwise Refinement"</a>, Niklaus Wirth, 1995Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-79986224220170991572009-11-24T19:13:00.000-08:002009-11-24T23:22:15.174-08:00Browserless Web Development<span style="font-style: italic;">note: "Web development" in this article doesn't include UI design/implementation, which means all (backend, database, html etc.) except css/javascript.<br /></span><br />I just found a new measure on code/web-developer recently. A traditional web development loop may look like this:<br /><br /><ol><li>read new feature/story</li><li>code</li><li>try it in browser, if there's any problem, goto 2 (goto considered useful here)</li><li>commit your code</li></ol><br />An obvious problem here is, there's no room left for *automated* test. You may write *automated* test in step 2, but no one force you to do it. A better process (I think) should be like this:<br /><br /><ol><li>read new feature/story</li><li>code</li><li style="font-weight: bold;">write a piece of code to test code in step 2, if there's any problem, goto 2</li><li>commit your code</li></ol><br />So we change step 3 only, removed browser from our process. *Automated* test become an explicit step here. You can switch step 2/3 in the latter process, so you'll write test first in that case, that's not the point here so I left them unchanged. The point is if you don't have a browser at hand you'll be forced to test your code by writing code, which is automated, reusable and cool. You'll find you're working in TDD style naturally even you don't know what TDD is.<br /><br />That's what I called Browserless Web Development. The less a web developer use browser to validate his work, the better he and his code are.Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com1tag:blogger.com,1999:blog-6265706250887913030.post-61436071375013799622009-10-26T19:44:00.000-07:002009-10-27T00:46:39.597-07:00Software Engineering is ...You know, Dijkstra is really awesome.<br /><br />"Ours is the task to remember (and to remind) that, in what is now called “software engineering”, not a single sound engineering principle is involved. (On the contrary: its spokesmen take the trouble of arguing the irrelevance of the engineering principles known.) Software Engineering as it is today is just humbug; from an academic —i.e. scientific and educational— point of view it is a sham, a fraud."<br /><br />"Universities are always faced with something of a problem when there is a marked discrepancy between what society asks for and what society needs. In our case the need is clear: the professional competence of the Mathematical Engineer, familiar with discrete systems design and knowing how to use formal techniques for preventing unmastered complexity from creeping in. But said war “out there” all but prevents this need from being perceived, and what our immediate industrial environment overwhelmingly seems to ask for is different brands of snake oil, Software Engineering, of course, being one of them. And as, with the recession lasting longer and longer, the external pressures on the Universities to do the wrong things only mount, it is only to be expected that part of the campus is going to be included in the battlefield."<br /><br />"The task of the first-class University, however, is absolutely clear. Industry being its customer, consultancy must tell industry what it wants to hear; it is the task of the first-class University to tell industry what it does not want to hear, whereby it is the rôle of its scientific authority to ensure that the sting of the academic gadfly really hurts."<br /><br />-- Edsger W. Dijkstra, <a href="http://www.cs.utexas.edu/users/EWD/transcriptions/EWD11xx/EWD1165.html">http://www.cs.utexas.edu/users/EWD/transcriptions/EWD11xx/EWD1165.html</a><br /><br />Update:<br /><br />It's interesting just after I read Dijkstra's article, Joel Spolsky published a new blog post <a href="http://www.joelonsoftware.com/items/2009/10/26.html">"Capstone projects and time management"</a>, to some extent on the opposite side of Dijkstra. Joel wrote lots with wisdom, but this new post just looks like an april fool's joke. A smart guy wrote a <a href="http://stochasticgeometry.wordpress.com/2009/10/27/joel-spolsky-snake-oil-salesman/">perfect answer</a> to Joel already.Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-73533928532462531892009-10-09T20:28:00.000-07:002009-12-28T06:45:56.600-08:00The Correct Refactor Flow<blockquote><ol><li>Get assigned a task to implement a new feature.</li><li>Refactor the code until that feature is as easy to add as possible.</li><li>Add the feature.</li><li>Submit.</li></ol></blockquote>Read this enlightening piece <a href="http://www.reddit.com/r/programming/comments/9scll/askproggit_help_me_find_flaw_in_this_logic_if_we/c0e7ndm">here</a>.<br /><br />update: I found this is indeed originated from Martin Fowler's amazing book "Refactoring", which is filled with ideas originated from practices of smalltalk. It's a shame I didn't read that book earlier :-( <a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/ref=sr_1_1?ie=UTF8&s=books&qid=1262011447&sr=8-1">"Refactoring"</a> (or <a href="http://www.amazon.com/Refactoring-Ruby-Jay-Fields/dp/0321603508/ref=sr_1_1?ie=UTF8&s=books&qid=1262011451&sr=8-1">"Refactoring: Ruby Edition"</a>) is a must read.Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-81735441189643814282009-09-10T23:06:00.000-07:002009-09-12T02:30:34.829-07:00Notes on Alan Kay's "The Early History of Smalltalk"<span>"In computer terms, Smalltalk is a recursion on the notion of computer itself. Instead of dividing "computer stuff" into things each less strong than the whole--like data structures, procedures, and functions which are the usual paraphernalia of programming languages--each Smalltalk object is a recursion on the entire possibilities of the computer. Thus its semantics are a bit like having thousands and thousands of computer all hooked together by a very fast network."</span> <span style="font-style: italic;">(I never think OO in this way before I read this, it changes my view of programming, made so many design pattern look naturally. This is a whole different way to explain why recursion is the root of computer (you know the original way is by lambda calculus))</span><br /><br />"Programming languages can be categorized in a number of ways: imperative, applicative, logic-based, problem-oriented, etc. But they all seem to be either an "agglutination of features" or a "crystallization of style." COBOL, PL/1, Ada, etc., belong to the first kind; LISP, APL-- and Smalltalk--are the second kind. It is probably not an accident that the agglutinative languages all seem to have been instigated by committees, and the crystallization languages by a single person." <span style="font-style: italic;">(Very interesting observation. It seems single-person languages are more popular today)</span><br /><br />"I could hardly believe how beautiful and wonderful the idea of LISP was. I say it this way because LISP had not only been around enough to get some honest barnacles, but worse, there wee deep falws in its logical foundations. By this, I mean that the pure language was supposed to be based on functions, but its most important components---such as lambda expressions quotes, and conds--where not functions at all, and insted ere called special forms. Landin and others had been able to get quotes and cons in terms of lambda by tricks that were variously clever and useful, but the flaw remained in the jewel. In the practical language things were better. There were not just EXPRs (which evaluated their arguments0, but FEXPRs (which did not). My next questions was, why on earth call it a functional language? Why not just base everuything on FEXPRs and force evaluation on the receiving side when needed?" <span style="font-style: italic;">(I like Alan Kay's criticism because what he wanted LISP to be looks exactly like Haskell :) He used an interesting description for LISP: 'surface beauty'. My opinion is LISP is still great, but not in practical sense now. All gurus suggest learning lisp but only for 'think different', not for using it in daily work. Alan Kay tell an incident later and said: </span>"Watching a famous guy much smarter than I struggle for more than 30 minutes to not quite solve the problem his way (there was a bug) made quite an impression. It brought home to me once again that "point of view is worth 80 IQ points." I wasn't smarter but I had a much better internal thinking tool to amplify my abilities." <span style="font-style: italic;">)</span><br /><br />"I didn't like meetings: didn't believe brainstorming could substitute for cool sustained thought."<br /><br />"The actual beauty of LISP came more from the promise of its metastrcutures than its actual model. I spent a fair amount of time thinking about how objects could be characterized as universal computers without having to have any exceptions in the central metaphor. What seemed to be needed was complete control over what was passed in a message send; in particular <span style="font-weight: bold;">when </span>and <span style="font-weight: bold;">in what environment</span> did expressions get evaluted? "<br /><br />"A simple and small system that can do interesing things also needs a "high slope"--that is a good match between the degree of interestingness and the level of complexity needed to express it. "<br /><br />"The latter was deemed to be hard and would be handled by the usual method for hard problems, namely, give them to grad students. "<br /><br />"Of course, the whole idea of Smalltalk (and OOP in general) is to define everything <span style="font-weight: bold;">intensionally</span>. "<br /><br />"Perhaps the most important principle--again derived from operating system architectures--is that when you give someone a structure, rarely do you want them to have unlimited priviledges with it. Just doing type-matching isn't even close to what's needed. Nor is it terribly useful to have some objects protected and others not. Make them all first class citizens and protect all. "<br /><br />"... this led to a 90 degree rotation of the purposed of the user interface from"access to functionality" to "environment in which users learn by doing."" <span style="font-style: italic;">(This is how overlapping windows user interface came out. I think this is also a proof why a programmer should work with keyboard+tilling windown manager: overlapping windows system, and in fact all GUI, is for end users who 'learn by doing'. Programmers are professionals, they should have already learnd their tools before doing anything, they shouldn't learn by doing. I never found a great programmer who mainly use mouse/GUI.)</span><br /><br />"By now it was already 1979, and we found ourselves doing one of our many demos, but this time for a very interested audience: Steve Jobs, JeffRaskin, and other technical people from Apple. They had started a project called Lisa but weren't quite sure what it shouldbe like, until Jeff said to Steve, "You should really come over to PARC and see what they ae doing." Thus, more than eight years after overlapping windows had been invented and more than six years after the ALTO started running, the people who could really do something about the ideas, finally to to see them. The machine used was the Dorado, a very fast "big brother" of the ALTO, whose Smalltalk microcode had been largely written by Bruce Horn, one of our original "Smalltalk kids" who was still only a teen-ager. Larry Tesler gave the main part of the demo with Dan sitting in the copilot's chair and Adele and I watched from the rear. One of the best parts of the demo was when Steve Jobs said he didn't like the blt-style scrolling we were using and asked if we cold do it in a smooth continuous style. In less than a minute Dan found the methods involved, made the (relatively major) changes and scrolling was now continuous! This shocked the visitors, espeicially the programmers among them, as they had never seen a really powerful incremental system before. Steve tried to get and/or buy the technology from Xerox (which was one of Apple's minority venture captialists), but Xerox would neither part with it nor would come up with the resources to continue to develop it in house by funding a better NoteTaker cum Smalltalk. " <span style="font-style: italic;">(How stupid Xerox is. In fact Alan Kay has predicted personal computing 30 years ago and reported his vision to Xerox many times. But Xerox just ignored those reports. If Xerox took Alan's work/suggestions seriously, it's very likely to be Microsoft+Apple today, not merely a laser printer company.)</span><br /><br />"One way to think about progress in software is that a lot of it has been about finding ways to late-bind"<br /><br />"Hardware is really just software crystallized early. It is there to make program schemes run as efficiently as possible. But far too often the hardware has been presented as a given and it is up to software designers to make it appear reasonable. This has caused low-level techniques and excessive optimization to hold back progress in program design. ... In short, most hardware designs today are just re-optimizations of moribund architectures. "<br /><br />"Objects made on different machines and with different languages should be able to talk to each other--and will have-to in the future."<br /><br />"I think the enormous commercialization of personal computering has smothered much of the kind of work that used to go on in universities and research labs, by sucking the talented kids towards practical applications. With companies so risk-adverse towards doing their own HW, and the HW companies betraying no real understanding of SW, the result has been a great step backwards in most respects. "<br /><br />Ref. <a href="http://gagne.homedns.org/%7Etgagne/contrib/EarlyHistoryST.html?repost=repost">"The Early History of Smalltalk"</a>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-63274585276746074692009-09-02T07:46:00.001-07:002009-09-03T07:26:25.174-07:00Cross-VM Attack on EC2Researchers from UCSD and MIT published a paper which shows vulnerability of cloud computing: cross-vm attack. With this technique a malicious user can run a new ec2 instance on the same physical machine as target vm instance, and exploit information leakage of target vm.<br /><br />Read it: <a href="http://people.csail.mit.edu/tromer/papers/cloudsec.pdf">http://people.csail.mit.edu/tromer/papers/cloudsec.pdf</a>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-28233542339083039602009-07-29T19:40:00.000-07:002009-07-29T19:43:56.077-07:00Dunning-Kruger effect"The Dunning-Kruger effect is an example of cognitive bias in which '...people reach erroneous conclusions and make unfortunate choices but their incompetence robs them of the metacognitive ability to realize it'."<br /><br />"They therefore suffer an illusory superiority, rating their own ability as above average. This leads to a perverse result where people with less competence will rate their ability more highly than people with relatively more competence."<br /><br />"It also explains why competence may weaken the projection of confidence because competent individuals falsely assume others are of equivalent understanding 'Thus, the miscalibration of the incompetent stems from an error about the self, whereas the miscalibration of the highly competent stems from an error about others.'"<br /><br />see <a href="http://en.wikipedia.org/wiki/Dunning-Kruger_effect">Wikipedia</a>Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0tag:blogger.com,1999:blog-6265706250887913030.post-42057407996601508202009-07-27T04:34:00.000-07:002009-07-27T04:58:07.053-07:00Ubiquitous MonadIt seems I had an 'aha!' time with monad today, finally. It seems monad is everywhere.<br /><br />In a functional world with currying, we can think all functions are in the type x -> y. We can divide those functions into two category:<br /><br /> 1. a -> a, these are functions who have same input and output type<br /> 2. a -> b, there are the functions who have different input and output type<br /><br />Functions in category one can work with functions have the same type as them easily, suppose you have f::Int->Int and g::Int->Int, you can combine them as you wish, like f.f.f.g.g.g.f.g.g.f. This is why people like functional programming.<br /><br />But this is not true for functions in 2rd category. Suppose you have f::Int->Float and g::Int->Float, how would you combine them? You can do neither f.g nor g.f, the types just don't match. As you can feel, there's much more functions in 2rd category than those in 1st category in real world. So monad comes to rescue.<br /><br />Monad helps functions in 2rd category behave like those ones in 1st category - it can 'lift' a 2rd category function to 1st category, with one of its core functions named bind:<br /><br /> bind :: (a -> b) -> (b -> b)<br /><br />In haskell b is a Monad. If you have read a tutorial take Maybe monad as example, you may have an intuition that monad is a 'wrapper' which wrap something. That's not exactly. The key here is to define a way to convert a value of type a to a value to type b, and vice vesa. Wrap a value is an easy and intuitive way to do the conversion, but not the only way (e.g. List Monad is a good example). So you can think everything as Monad, because type a -> b function is everywhere. Yes Float is monad, because there is a function in type Int -> Float and you can define a bind in type (Int -> Float) -> (Float -> Float).Janhttp://www.blogger.com/profile/06665323561458161788noreply@blogger.com0