root/trunk/docsrc/lisp-java-d.dd

Revision 2040, 8.7 kB (checked in by walter, 2 years ago)

typography

  • Property svn:eol-style set to native
Line 
1 Ddoc
2
3 $(COMMUNITY Lisp vs. Java... D?,
4
5 <center>
6 $(I by Lionello Lunesu, Oct. 18th 2006)
7 </center>
8
9         <p>Two weeks ago, Josh Stern posted an
10     $(LINK2 http://www.digitalmars.com/d/archives/digitalmars/D/Lisp_vs._C_not_off-topic_42717.html, interesting link)
11     on the
12     <a href="http://www.digitalmars.com/d/archives/digitalmars/D/index.html">digitalmars.D newsgroup</a>.
13     The link pointed to a
14     <a href="http://userpages.umbc.edu/~bcorfm1/C++-vs-Lisp.html">page describing a programming challenge</a>
15     that was originally used in a
16             study in which 38 C, C++ and Java programmers were asked to write versions of a
17             program to compare Java and C++ efficiency.
18         </p>
19
20         <p>Many other programmers had taken up the challenge since. In <a href="http://www.norvig.com/java-lisp.html">
21                 one such comparison</a>, Lisp turned out to be a clear winner over Java and
22             C++ when comparing development time and lines of code, with the record standing
23             at about 2 hours, with 45 non-comment non-blank lines. For C++, the shortest
24             development time was 3 hours and the
25         shortest program had 107 lines of code.
26     </p>
27         <p>With some time to spare, I thought I should give it a try myself. Although I'm a
28             C++ programmer myself (and have been for 10 years now), I thought it would be a
29             great opportunity to test my skills in the <a href="http://www.digitalmars.com/d/">D
30                 programming language</a>.</p>
31         <p>I had not looked at the other implementations and only read the <a href="http://www.flownet.com/ron/papers/lisp-java/">
32                 original problem statement</a>. It took me <strong>1 hour and 15 minutes</strong>,
33             from reading the statement to finishing the program. The program was just 55
34             lines long (remember, the
35         shortest C++ entry
36         had 107 lines), not counting blank
37             lines, comments, assertions, unittests, contracts and trailing curly brackets
38             (similar to Lisp).
39         </p>
40         <p>The program basically had to do this: read all words from a dictionary file; for
41             each letter there was a corresponding digit (like the letters on a phone);
42             using this mapping, read phone numbers from another text file and print all
43             possible combinations of words for that phone number. Check the link above for
44             more details.</p>
45         <p>What made implementing this task so easy in D? I just happened to have every
46             construct I needed at hand. Some of the goodies used, are:</p>
47         $(UL
48             $(LI Assertions, contracts and unittests)
49             $(LI Built-in arrays and strings, with easy slicing)
50             $(LI Built-in associative array)
51             $(LI Garbage collection)
52             $(LI Type deduction and foreach)
53             $(LI Nested functions)
54             $(LI Returning (reference to) a array from a function)
55         )
56         <p>During the actual programming I did not have to stop and think about anything.
57             The program evolved automatically, once I thought of the actual container for
58             the dictionary. It turned out that the $(SINGLEQUOTE winning) Lisp version was storing the
59             dictionary in a similar manner.</p>
60         <h2>Compiling</h2>
61         <p>To test the program yourself, first download the <a href="http://www.flownet.com/ron/papers/lisp-java/dictionary.txt">
62                 dictionary.txt</a> and <a href="http://www.flownet.com/ron/papers/lisp-java/input.txt">
63                 input.txt</a>. Then, <a href="http://www.digitalmars.com/d/download.html">download
64                 the latest D compiler</a>. To compile,
65         copy-paste the D code into a newly created file
66         phoneno.d, and compile it with:
67         </p>
68 $(CONSOLE
69 dmd -run phoneno.d
70 )
71
72 ---------------------
73 // Created by Lionello Lunesu and placed in the public domain.
74 // This file has been modified from its original version.
75 // It has been formatted to fit your screen.
76 module phoneno;     // optional
77 import std.stdio;   // writefln     
78 import std.ctype;   // isdigit     
79 import std.stream;  // BufferedFile
80
81 // Just for readability (imagine char[][][char[]])   
82 alias char[] string;
83 alias string[] stringarray;
84
85 /// Strips non-digit characters from the string (COW)
86 string stripNonDigit( in string line )
87 {
88     string ret;
89     foreach(uint i, c; line) {
90         // Error: std.ctype.isdigit at C:\dmd\src\phobos\std\ctype.d(37)
91         // conflicts with std.stream.isdigit at C:\dmd\src\phobos\std\stream.d(2924)
92         if (!std.ctype.isdigit(c)) {
93             if (!ret)
94                 ret = line[0..i];   
95         }   
96         else if (ret)
97             ret ~= c;   
98     }   
99     return ret?ret:line;
100 }
101
102 unittest {
103     assert( stripNonDigit("asdf") == ""  );
104     assert( stripNonDigit("\'13-=2 4kop") ==  "1324"  );
105 }
106
107 /// Converts a word into a number, ignoring all non alpha characters 
108 string wordToNum( in string word )
109 {
110 // translation table for the task at hand
111 const char[256] TRANSLATE =   
112     "                                "  // 0   
113     "                0123456789      "  // 32     
114     " 57630499617851881234762239     "  // 64   
115     " 57630499617851881234762239     "
116     "                                "
117     "                                "
118     "                                "   
119     "                                ";
120     string ret;
121     foreach(c; cast(ubyte[])word)
122         if (TRANSLATE[c] != ' ')
123             ret ~= TRANSLATE[c];
124     return ret;
125 }
126
127 unittest {
128  // Test wordToNum using the table from the task description.
129  assert( "01112223334455666777888999" ==
130    wordToNum("E | J N Q | R W X | D S Y | F T | A M | C I V | B K U | L O P | G H Z"));
131  assert( "01112223334455666777888999" ==
132    wordToNum("e | j n q | r w x | d s y | f t | a m | c i v | b k u | l o p | g h z"));
133  assert( "0123456789" ==
134    wordToNum("0 |   1   |   2   |   3   |  4  |  5  |   6   |   7   |   8   |   9"));
135 }
136
137 void main( string[] args )
138 {
139     // This associative array maps a number to an array of words.   
140     stringarray[string]    num2words;
141
142     foreach(string word; new BufferedFile("dictionary.txt" ) )
143         num2words[ wordToNum(word) ] ~= word.dup;        // must dup
144
145     /// Finds all alternatives for the given number
146     /// (should have been stripped from non-digit characters)
147     stringarray _FindWords( string numbers, bool digitok )
148     in {
149         assert(numbers.length >  0);   
150     }   
151     out(result) {
152         foreach (a; result)
153             assert( wordToNum(a) == numbers );
154     }   
155     body {
156         stringarray ret;
157         bool foundword = false;
158         for (uint t=1; t<=numbers.length; ++t) {
159             auto alternatives = numbers[0..t] in num2words;
160             if (!alternatives)
161                 continue;
162             foundword = true;
163             if (numbers.length >  t) {
164                 // Combine all current alternatives with all alternatives     
165                 // of the rest (next piece can start with a digit)             
166                 foreach (a2; _FindWords( numbers[t..$], true     ) )
167                     foreach(a1; *alternatives)
168                        ret ~= a1 ~ " " ~ a2;
169             }
170             else   
171                 ret ~= *alternatives;    // append these alternatives
172         }
173         // Try to keep 1 digit, only if we're allowed and no other
174         // alternatives were found
175         // Testing "ret.length" makes more sense than testing "foundword",
176         // but the other implementations seem to do just this.
177         if (digitok && !foundword) { //ret.length == 0 
178             if(numbers.length >  1) {
179                 // Combine 1 digit with all altenatives from the rest   
180                 // (next piece can not start with a digit)         
181                 foreach (a; _FindWords( numbers[1..$], false ) )
182                     ret ~= numbers[0..1] ~ " " ~ a;
183             }   
184             else   
185                 ret ~= numbers[0..1];    // just append this digit             
186         }   
187         return ret;
188     }
189
190     /// (This function was inlined in the original program)
191     /// Finds all alternatives for the given phone number
192     /// Returns: array of strings
193     stringarray FindWords( string phone_number )
194     {
195         if (!phone_number.length)
196             return null;
197         // Strip the non-digit characters from the phone number, and
198         // pass it to the recursive function (leading digit is allowed)
199         return _FindWords( stripNonDigit(phone_number), true );   
200     }   
201    
202     // Read the phone numbers     
203     foreach(string phone; new BufferedFile("input.txt"   ) )
204         foreach(alternative; FindWords( phone ) )
205             writefln(phone, ": ", alternative );
206 }
207 ---------------------
208
209 )
210
211 Macros:
212     TITLE=Lisp vs. Java... D?
213     WIKI=LispVsJavaVsD
214     COPYRIGHT=
Note: See TracBrowser for help on using the browser.