Showing posts with label weeks. Show all posts
Showing posts with label weeks. Show all posts
Thursday, February 5, 2015
Seven Languages in Seven Weeks Ruby Day 1

Each section of the book focuses on a different language and includes coding problems for the reader to try at home. Ive decided to record my my solutions to the problems and thoughts about each language in my blog. Today, well start with Ruby.
Ruby, Day 1: Thoughts
Ive used Ruby fairly extensively the last few years, including several Ruby on Rails apps (Resume Builder, Veterans Hackday) and a number of utility scripts. There is a lot to like about Ruby - the concise & clean syntax, incredible flexibility, expressiveness, powerful DSLs - but my favorite part is the central tennet of the language, as expressed by its creator:
"Ruby is designed to make programmers happy." Yukihiro MatsumotoThe language isnt built for speed, concurrency, or any particular feature set. Its central "success metric" is programmer happiness and productivity, which are, arguably, the biggest bottlenecks in most projects.
Ruby, Day 1: Problems
The "Day 1" Ruby chapter focused on the very basics of the language, so I didnt learn anything new. The problems are extremely simple and basic, but for completeness, here are my solutions:
Hello, World
Print the string "Hello, world".
Hello, Ruby
For the String "Hello, Ruby", find the index of the word "Ruby".
Print Name
Print your name ten times.
Print Sentence
Print the string "This is sentence number 1" where the number 1 changes from 1 to 10.
Random Number
Write a program that picks a random number. Let a player guess the number, telling the player whether the guess is too high or too low.
Ruby vs. Java
Coming from a Java background, every time I see Ruby, Im amazed at how concise and readable it is. There is far less boilerplate: you dont have to wrap everything in classes and methods, no semi-colons, far fewer curly braces, and so on. Everything is an object and there are countless helper functions, all with intuitive names: even if youve never used Ruby, its easy to guess the effects of 10.times or 1.upto(10). Whereas in the Java world, libraries seem to compete on having every bell, whistle, and tuning knob, in the Ruby world, libraries focus much more on having the simplest, easiest, one-line-and-youre-done API possible.
For comparison, I implemented the number guessing game in Java:
Its has more than twice the number of lines of code as the Ruby version (and I kept opening curly braces on the same line!) and even though Ive been doing Java for a very long time, it still took longer to write. Of course, there are many other trade-offs at play here, but they key thing to think about is the golden rule of programming:
"Programs must be written for people to read, and only incidentally for machines to execute." SICPRuby has its downsides, but it is one of the best languages Ive seen for writing code that others can read, understand, and maintain for a long time after.
Ruby, Continued
The Ruby explorations continue on Ruby, Day 2.
Tuesday, January 27, 2015
Seven Languages in Seven Weeks Prolog Day 2
Prolog, Day 2: Thoughts
Today, Prolog broke my brain. The chapter started with recursion, lists, tuples, and pattern matching, all of which were tolerable if youve had prior exposure to functional programming. However, after that, we moved onto using unification as the primary construct for problem solving, and the gears in my head began to grind.
It took me a while to wrap my head around using unification, but once it clicked, I was both elated and disappointed. I was elated because (a) I often get that way when I learn something new and (b) the book was clearly getting me to think about programming in a totally new manner. However, I was disappointed because even accomplishing something as trivial as adding all the values in a list required a recursive solution that seemed unnecessarily complicated:
The algorithm starts with a base case: the sum of an empty list is 0. We then add a recursive case: the sum of a non-empty list is the head of the list plus the sum of the tail. This isnt too bad once you get used to it, but I find that this sort of code does not communicate its intent well at all. That is, Im a believer that "programs must be written for people to read, and only incidentally for machines to execute" (Structure and Interpretation of Computer Programs) and this prolog code seems to be the exact opposite. Even for something as trivial as adding the values in a list, I find myself distracted by the need to do pattern matching on the list, recursive calls, and base cases.
In fact, while I have no doubt that the declarative approach is very powerful for certain types of problems, its not exactly what I expected when I first heard of declarative programming. Conceptually, I thought declarative programming would be all about describing what the solution looks like. From the Prolog Ive seen so far, which is admittedly very little, I feel like what were actually doing is setting up elaborate "traps" to force the unification engine to fill in the proper values for our variables.
As a counter-example, heres how an "ideal" declarative programming might let me define the sum of a list:
To me, the "code" above screams its intent far more clearly than the recursive prolog solution. An even clearer example comes later in this blog post, where I sort a list using Prolog. While writing this sorting code, I felt like I was playing a game of "how do I setup my rules and atoms to arm twist unification into sorting?" If I had designed Prolog using a coding backwards approach, I wouldve strived to let the user define a sorted list in a much more natural manner:
(Update: turns out it is possible to do something close to this. See the end of the post.)
However, I admit freely that Im no expert on compilers or language design, so perhaps Im being naive. Maybe theres no way to define a syntax or compiler that can handle such simple looking definitions in the general case. Perhaps the unification approach in Prolog is as close as we can get and I just need time until my brain gets used to it more.
Prolog, Day 2: Problems
Reverse the elements of a list
Find the smallest element of a list
A pretty simple problem, except that there doesnt seem to be a way to do an if/else statement in Prolog. Instead, to handle the possible outcomes of TailMin =< Head and TailMin > Head, I had to use pattern matching and a bit of copy & paste. If anyone knows a more DRY way to do this, please let me know.
Sort the elements of a list
I implemented merge sort. In retrospect, this seems to somewhat defeat the purpose of declarative programming. That is, instead of describing the solution - that is, what a sorted list looks like - Im effectively describing the individual steps it takes to sort a list. In other words, this is awfully close to imperative programming.
Unfortunately, I couldnt think of a more "declarative" way of solving this. I initially wrote something similar to a selection sort: it recursively called sort_list on the tail until we got down to one item. At that point, it would use the merge method to arrange the head and tail in the proper order. As we went back up the recursion stack, the merge method would insert the head in the proper spot in the partial sublist. This was obviously less efficient, but at least the sort_list method looked declarative. If only there was a way to define it without a merge step, Id be in business.
Fibonacci series
I ran into two gotchas writing a fibonacci function: first, I had to remember that the recursive calls to "fib" are not really function calls and you cant just directly pass "N - 1" or "N - 2" as parameters. However, when defining N1 and N2, I ran into a second gotcha: you need to use the "is" keyword instead of the equals ("=") sign.
Factorial
UPDATE: eating humble pie
Ok, I was wrong. It turns out you can write Prolog code that looks much more declarative and much less imperative. After reading through Day 3 of Prolog, I was a bit wiser, and was able to write the following code for sorting:
Im sure its not as fast as the merge sort I wrote on my first attempt, but the intent is much clearer: Im quite obviously describing what a sorted list should look like instead of walking through the steps of how to build one. The recursion and various language quirks of Prolog still take some getting used to, but from a readability perspective, Im much happier with what Ive been seeing since reading Day 3.
Moving right along
Check out Prolog: Day 3 for some more declarative goodness, including an elegant Sudoku solver.
Subscribe to:
Posts (Atom)