{"id":47,"date":"2007-11-09T13:31:30","date_gmt":"2007-11-09T11:31:30","guid":{"rendered":"http:\/\/ken.friislarsen.net\/blog\/2007\/11\/09\/decoding-morse-code-with-f-comprehensions\/"},"modified":"2016-03-31T18:55:37","modified_gmt":"2016-03-31T16:55:37","slug":"decoding-morse-code-with-f-comprehensions","status":"publish","type":"post","link":"http:\/\/ken.friislarsen.net\/blog\/2007\/11\/09\/decoding-morse-code-with-f-comprehensions\/","title":{"rendered":"Decoding Morse Code With F# Comprehensions"},"content":{"rendered":"<p>In my last post I showed how to <a href=\"http:\/\/ken.friislarsen.net\/blog\/2007\/09\/19\/morse-code-decoding-with-python-list-comprehensions\/\">decode morse code in Python using list comprehensions<\/a>. In this post I show how to do it in <a href=\"http:\/\/fsharp.org\/\">F#<\/a> instead.<\/p>\n<p>First using list comprehensions:<\/p>\n<pre>let codes =\r\n    [(\"A\",\".-\");   (\"B\",\"-...\"); (\"C\",\"-.-.\"); (\"D\",\"-..\"); (\"E\",\".\");\r\n     (\"F\",\"..-.\"); (\"G\",\"--.\");  (\"H\",\"....\"); (\"I\",\"..\");  (\"J\",\".---\");\r\n     (\"K\",\"-.-\");  (\"L\",\".-..\"); (\"M\",\"--\");   (\"N\",\"-.\");  (\"O\",\"---\");\r\n     (\"P\",\".--.\"); (\"Q\",\"--.-\"); (\"R\",\".-.\");  (\"S\",\"...\"); (\"T\",\"-\");\r\n     (\"U\",\"..-\");  (\"V\",\"...-\"); (\"W\",\".--\");  (\"X\",\"-..-\");(\"Y\",\"-.--\");\r\n     (\"Z\",\"--..\")]<\/pre>\n<pre>let rec decode input =\r\n    if input = \"\" then [\"\"]\r\n    else [ for c, code in codes when input.StartsWith(code)\r\n           for rest in decode(input.Substring(String.length code))\r\n           -&gt; c + rest ]<\/pre>\n<p>As it can be seen the code is almost identical to the Python code. Incidentally, I could not find a function equivalent to Python&#8217;s <code>startswith<\/code> method in the O&#8217;Caml standard library (without using regular expressions). Fortunately F# came with one from the .NET library.<\/p>\n<p>Much to my the surprise the compiled F# (running on Mono 1.2.4) is 4 times slower that the Python code. I then rewrote the program to use sequence comprehensions:<\/p>\n<pre>let rec decode input =\r\n    if input = \"\" then { -&gt; \"\" }\r\n    else { for c, code in codes when input.StartsWith(code)\r\n           for rest in decode(input.Substring(String.length code))\r\n           -&gt; c + rest }<\/pre>\n<p>This version runs faster, and uses only a constant amount of memory. Still the Python version is three and half times faster.<\/p>\n<p>I then tried to run the programs on an other computer with Microsoft&#8217;s .NET implementation. This improved the F# running times a lot. However, they are still 40% to 80% slower than the Python version.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/ken.friislarsen.net\/blog\/wp-content\/fs-vs-python-morse.png\" alt=\"Chart of F# vs Python on morse code decoding\" \/><\/p>\n<p>My current guess is that Python is much better at handling strings than .NET.<\/p>\n<p>The actual numbers:<\/p>\n<table border=\"1\">\n<tbody>\n<tr>\n<th><\/th>\n<th colspan=\"2\">Linux, Mono<\/th>\n<th colspan=\"2\">Vista, MS .NET<\/th>\n<\/tr>\n<tr>\n<td>Program<\/td>\n<th>Time<br \/>\nsec<\/th>\n<th>Ratio<\/th>\n<th>Time<br \/>\nsec<\/th>\n<th>Ratio<\/th>\n<\/tr>\n<tr>\n<th><code>morse.py<\/code><\/th>\n<td>7.94 \u00b1 0.05<\/td>\n<td>1<\/td>\n<td>11.03 \u00b1 0.03<\/td>\n<td>1<\/td>\n<\/tr>\n<tr>\n<th><code>morse.fs<\/code><\/th>\n<td>33.07 \u00b1 0.19<\/td>\n<td>4.17<\/td>\n<td>19.65 \u00b1 0.33<\/td>\n<td>1.78<\/td>\n<\/tr>\n<tr>\n<th><code>morse-seq.fs<\/code><\/th>\n<td>28.1 \u00b1 0.59<\/td>\n<td>3.54<\/td>\n<td>16.12 \u00b1 0.36<\/td>\n<td>1.46<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong>Update 2007-11-12 Added test files:<\/strong><\/p>\n<ul>\n<li>Python code: <a href=\"http:\/\/ken.friislarsen.net\/tmp\/morse-py.txt\"><code>morse.py<\/code><\/a><\/li>\n<li>F# code using list comprehensions: <a href=\"http:\/\/ken.friislarsen.net\/tmp\/morse.fs\"><code>morse.fs<\/code><\/a><\/li>\n<li>F# code using sequence comprehensions: <a href=\"http:\/\/ken.friislarsen.net\/tmp\/morse-seq.fs\"><code>morse-seq.fs<\/code><\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In my last post I showed how to decode morse code in Python using list comprehensions. In this post I show how to do it in F# instead. First using list comprehensions: let codes = [(&#8220;A&#8221;,&#8221;.-&#8220;); (&#8220;B&#8221;,&#8221;-&#8230;&#8221;); (&#8220;C&#8221;,&#8221;-.-.&#8221;); (&#8220;D&#8221;,&#8221;-..&#8221;); (&#8220;E&#8221;,&#8221;.&#8221;); (&#8220;F&#8221;,&#8221;..-.&#8221;); (&#8220;G&#8221;,&#8221;&#8211;.&#8221;); (&#8220;H&#8221;,&#8221;&#8230;.&#8221;); (&#8220;I&#8221;,&#8221;..&#8221;); (&#8220;J&#8221;,&#8221;.&#8212;&#8220;); (&#8220;K&#8221;,&#8221;-.-&#8220;); (&#8220;L&#8221;,&#8221;.-..&#8221;); (&#8220;M&#8221;,&#8221;&#8211;&#8220;); (&#8220;N&#8221;,&#8221;-.&#8221;); (&#8220;O&#8221;,&#8221;&#8212;&#8220;); (&#8220;P&#8221;,&#8221;.&#8211;.&#8221;); (&#8220;Q&#8221;,&#8221;&#8211;.-&#8220;); (&#8220;R&#8221;,&#8221;.-.&#8221;); (&#8220;S&#8221;,&#8221;&#8230;&#8221;); (&#8220;T&#8221;,&#8221;-&#8220;); <a class=\"read-more\" href=\"http:\/\/ken.friislarsen.net\/blog\/2007\/11\/09\/decoding-morse-code-with-f-comprehensions\/\">[&hellip;]<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,16,3,14],"tags":[],"class_list":["post-47","post","type-post","status-publish","format-standard","hentry","category-coding","category-fsharp","category-general","category-python"],"_links":{"self":[{"href":"http:\/\/ken.friislarsen.net\/blog\/wp-json\/wp\/v2\/posts\/47","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/ken.friislarsen.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ken.friislarsen.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ken.friislarsen.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/ken.friislarsen.net\/blog\/wp-json\/wp\/v2\/comments?post=47"}],"version-history":[{"count":4,"href":"http:\/\/ken.friislarsen.net\/blog\/wp-json\/wp\/v2\/posts\/47\/revisions"}],"predecessor-version":[{"id":117,"href":"http:\/\/ken.friislarsen.net\/blog\/wp-json\/wp\/v2\/posts\/47\/revisions\/117"}],"wp:attachment":[{"href":"http:\/\/ken.friislarsen.net\/blog\/wp-json\/wp\/v2\/media?parent=47"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ken.friislarsen.net\/blog\/wp-json\/wp\/v2\/categories?post=47"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ken.friislarsen.net\/blog\/wp-json\/wp\/v2\/tags?post=47"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}