<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-32850121</id><updated>2012-01-28T04:39:33.328-08:00</updated><title type='text'>Programming Experiments</title><subtitle type='html'>Experimentation and thoughts on programming, specifically with Erlang and the application domains that it covers.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>16</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-32850121.post-210679050871717343</id><published>2007-06-20T17:39:00.000-07:00</published><updated>2007-06-20T18:29:18.369-07:00</updated><title type='text'>Initial Release of my web tools</title><content type='html'>I placed the Erlang-based web tools that I am working on for the development of some of my own applications online. They are very rough, in that they are a big mix of experimentation and trying to get something working to write some actual applications. So, the documentation is weak, and there are still certain conventions and features that I need to work out that are not particularly complete yet. (So it is version 0.0.1 :)) I am not really concerning myself over making the system polished; what I wrote were just things that I found myself comfortable to work with. &lt;br /&gt;&lt;br /&gt;The two tools are (with the most dullest of names):&lt;br /&gt;&lt;br /&gt;1. Weberl is a request handler that uses Yaws. The difference between this and ErlyWeb is of its heavy dependence on OTP for configuration, and all that OTP provides and that it uses behaviours for controller modules. It uses SGTE as a templating tool.&lt;br /&gt;&lt;br /&gt;2. Formtool is two things: a special form processor for handling basic forms and their validation, as well as a form generator given a specific form layout. (I wrote a draft of an academic paper on this project a month or two ago on this, as a joke. I was going to put that in the archive for this project, but I just got too embarrassed to release it at the last moment. :))&lt;br /&gt;&lt;br /&gt;There are other things I wrote that might find their way into the above, but they are not for public consumption now. :)&lt;br /&gt;&lt;br /&gt;Links:&lt;br /&gt;&lt;a href="http://www.qinternet.com/erlang/weberl.tgz"&gt;Weberl&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.qinternet.com/erlang/formtool.tgz"&gt;Formtool&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;They are both licensed under the BSD license. &lt;br /&gt;&lt;br /&gt;If you see anything interesting in this stuff, and have a million questions for me, then you can email me at brian@qinternet.com.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-210679050871717343?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/210679050871717343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=210679050871717343' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/210679050871717343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/210679050871717343'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2007/06/initial-release-of-my-web-tools.html' title='Initial Release of my web tools'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-549028692862742222</id><published>2007-05-02T19:38:00.000-07:00</published><updated>2007-05-02T19:50:47.837-07:00</updated><title type='text'>Framework Experiment</title><content type='html'>Today I was experimenting with a few ideas for an Erlang web framework. &lt;br /&gt;&lt;br /&gt;I wanted to utilize OTP like features more, like using a .app file, making the application a server,  writing controllers using the behavior feature. I also want to see where I can use the release handling features, since I depend on the .app file for configuration.&lt;br /&gt;&lt;br /&gt;It works, sort of. It ain't complete. The server does not work. But, other than that, right now, it is quite simple.&lt;br /&gt;&lt;br /&gt;I am not ready to release it, but I put the [incomplete] docs online for now. It is at [http://www.pushon.org/overview.edoc]. If those see this as something interesting to work with, I'll eventually set up a subversion repository.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-549028692862742222?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/549028692862742222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=549028692862742222' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/549028692862742222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/549028692862742222'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2007/05/framework-experiment.html' title='Framework Experiment'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-6929164031594405751</id><published>2007-04-15T19:14:00.000-07:00</published><updated>2007-04-15T19:53:17.854-07:00</updated><title type='text'>Simple Dynamic Record Access, Redux</title><content type='html'>I sparked a little interest in my post. I thank everyone who has commented on my post, both the comment on Reddit, and the comments made here. Now on my list of things to do is to read deeper about this topic. &lt;br /&gt;&lt;br /&gt;I will admit that I did not make the most spectacular of implementations of the idea (with a max of like 3 minutes actually thinking about it, just to get something working, excluding writing the entry :)) &lt;br /&gt;&lt;br /&gt;I did think I was a bit hasty in saying 'hate' like in the phrase 'I hate records'. I 'wish' they were more dynamic, but I am not weeping over it, since myself, ayrnieu (http://programming.reddit.com/info/1i147/comments) and Philip Robinson (http://chlorophil.blogspot.com/2007/04/dynamic-record-access-functions-with.html) were able to tackle something over the idea. I knew its limitations, so I have tended to use proplists mostly instead, for small lists. It was when I had to consider trying to do dynamic access, I was saying "ohhhhh!" &lt;br /&gt;&lt;br /&gt;Eh, anyway, forgive the non-technical response. I am going to do some cutting-and-pasting later, replacing my own with a better implementation. :D&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-6929164031594405751?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/6929164031594405751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=6929164031594405751' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/6929164031594405751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/6929164031594405751'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2007/04/simple-dynamic-record-access-redux.html' title='Simple Dynamic Record Access, Redux'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-3090642120789466127</id><published>2007-04-14T17:24:00.000-07:00</published><updated>2007-04-14T18:00:57.546-07:00</updated><title type='text'>Simple Dynamic Record Access</title><content type='html'>There is one thing I hate about Erlang, and it is records. It is not so much that the syntax is annoying (yet I am getting used to it), but you cannot use that syntax for dynamic field access; records are a compile-time feature. &lt;br /&gt;&lt;br /&gt;So, without using Yariv's Smerl for something like this, I opted for a simpler solution. Records are tuples after all, and you can get record information in a list. So, you can use these two facts to create a function to get the field you specify. Not anything stellar, but for dynamic record access, it works:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;find(Item, List) -&gt;&lt;br /&gt; find_(Item, List, 1).&lt;br /&gt;find_(Item, [], _) -&gt; not_found;&lt;br /&gt;find_(Item, [H|T], Count) -&gt;&lt;br /&gt; case H of&lt;br /&gt;  Item -&gt;&lt;br /&gt;   Count;&lt;br /&gt;  _ -&gt;&lt;br /&gt;   find_(Item, T, Count+1)&lt;br /&gt; end.&lt;br /&gt;&lt;br /&gt;get_rec_value(Key, Rec, RecordInfo) -&gt;&lt;br /&gt; case find(Key, RecordInfo) of&lt;br /&gt;  not_found -&gt;&lt;br /&gt;   undefined;&lt;br /&gt;  Num -&gt;&lt;br /&gt;   element(Num+1, Rec)&lt;br /&gt; end.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I couldn't find something like "lists:find/2", so I implemented my own. But the main function is "get_rec_value/3". So you do this:&lt;br /&gt;&lt;br /&gt;1&gt; rd(person, {id, name, email}).&lt;br /&gt;2&gt; get_rec_value(name, #person{name="Brian"}, record_info(fields, person)).&lt;br /&gt;"Brian"&lt;br /&gt;&lt;br /&gt;For fun, I also did setting record value.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;set_rec_value(Key, Value, Rec, RecordInfo) -&gt;&lt;br /&gt; RecList = tuple_to_list(Rec),&lt;br /&gt; case find(Key, RecordInfo) of&lt;br /&gt;  not_found -&gt;&lt;br /&gt;   Rec;&lt;br /&gt;  Num -&gt;&lt;br /&gt;   List1 = lists:sublist(RecList, Num),&lt;br /&gt;   List2 = lists:sublist(RecList, Num+2, length(RecList)),&lt;br /&gt;   tuple_to_list(List1 ++ [Value] ++ List2)&lt;br /&gt; end.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;3&gt; set_rec_value(email, "c", #person{name="Brian", id="1", email="b"}, record_info(fields, person)).&lt;br /&gt;&lt;br /&gt;I know this stuff looks really simple, but since I thought this was a bit of a nuisance, the fact that I cannot access records without hardcoding the values, something needed to be written.&lt;br /&gt;&lt;br /&gt;Did I miss something though? I'd like to know. Please comment. :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-3090642120789466127?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/3090642120789466127/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=3090642120789466127' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/3090642120789466127'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/3090642120789466127'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2007/04/simple-dynamic-record-access.html' title='Simple Dynamic Record Access'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-4373760042195530828</id><published>2007-04-11T10:51:00.000-07:00</published><updated>2007-04-11T11:33:29.209-07:00</updated><title type='text'>The Case For Erlang For Web Applications</title><content type='html'>This is the topic I am working on for a paper for my final-year project. The problem with the topic is that it is seriously general, since it can cover so much, like performance and scalability concerns, development concerns, etc. So, while in the midst of preparing to debate this question, I have sat and asked myself "Is there a case to use Erlang for web applications?" &lt;br /&gt;&lt;br /&gt;So I am focusing on two areas: "How well can a single Erlang node (the interpreter + the hardware) handle a significant load?" I will admit that I never deployed any web application that is used by more than at most, 10-20 people. There are a lot of concerns that I might be overlooking when considering scalability and performance aspects, so I might be jumping in this naively. However, I am a bit inspired by this one point: "If Erlang can perform well on a single piece of hardware, then can this make scalability potentially easier?" This reminds me of the things I have been reading about Ruby on Rails and the scalability problems that people have been having with that, even though I keep hearing "Well, if you are getting a a lot more hits than your system can handle, then I think you can afford more hardware." Potentially, but it seems very convenient to say when you have to actually deploy a system because your current server setup cannot handle the load. &lt;br /&gt;&lt;br /&gt;So, bandwidth excluded, what if my small setup of Rails servers cannot take a current spike because of some Slashdot effect occurring? Or what if I have my Web2.0ish application, dinky and small as it is, become the talk on people's lips, causing a spike in load? (I think that would be wonderful, though ;) )&lt;br /&gt;&lt;br /&gt;The fact is, I don't know what would happen. But, at the same time, I am not denying the efficacy of well-designed setups that are running Rails applications. But I am assuming something: if they say that Erlang can potentially handle a lot of load, very well, and if it was designed with this in mind, with a very practical and complex application in mind, can it not help when running my not-so-complicated, dinky little web site? Okay, I might get 10 hits on it every week, but even if I only getting 10 hits, Erlang is not really a sledgehammer to drive in a finish nail. That's where Java would come in.&lt;br /&gt;&lt;br /&gt;The fact is, with a little effort, one will find doing web development in Erlang to be easy. Okay, it is not up to the level of Rails in terms of features. However, even regardless of the performance and scalability features that are in Erlang, it is showing me, incrementally, to be a very simple but very powerful language framework to get things done. &lt;br /&gt;&lt;br /&gt;I said in an earlier post that I am finding it easier to debug certain things because there is no indeterminacy in variables. Erlang is also dynamically typed, so it, initially was easy to pick and learn, and apply my existing understanding of recursion and of higher-order functions to this language. &lt;br /&gt;&lt;br /&gt;So, what I am trying to stress here is that, I think, for what I know, as compared to what other people have been saying, I think that using Erlang, with a platform that has been proven for the types of things that it was designed to do, along with its ease of programming, can be said to be a good platform for web application development. It might not be *perfect* (like the things people complain about in terms of string handling), but these things do not outweigh the positives.&lt;br /&gt;&lt;br /&gt;This, is, of course, all a crazy assumption, still. I still have yet to get my tiny web app running to actually run tests on it.&lt;br /&gt;&lt;br /&gt;The thing that I am worried about though is how to say all the stuff I said in the typical dry academic tone that I will be compelled to use for my final paper. Ugh. But one reason I wrote this is to figure out how to do just that. The thing also is that all the assumptions I have made here are still willingly open to skepticism, and I open and willing to challenge those assumptions. &lt;br /&gt;&lt;br /&gt;I just hope that anyone who is reading this might not immediately jump to the conclusion that I am nuts or I don't know what I am doing; my daily blog readings on Reddit and other places give off this sense, particularly if the object of debate is an article that seems too sure of itself.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-4373760042195530828?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/4373760042195530828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=4373760042195530828' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/4373760042195530828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/4373760042195530828'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2007/04/case-for-erlang-for-web-applications.html' title='The Case For Erlang For Web Applications'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-7598578934257565721</id><published>2007-04-07T18:00:00.000-07:00</published><updated>2007-04-07T19:36:26.418-07:00</updated><title type='text'>Some Observations</title><content type='html'>I have been working on a number of Erlang-based projects this week; it's spring break! Most of them are just simple libraries. I would think that my code is not the greatest, but I did notice a few things.&lt;br /&gt;&lt;br /&gt;1. Having variables not change state does help. Coupling that with unit testing, it makes debugging quite straightforward. The fact is, is that when you focus using functional techniques, by that virtue alone, you remove indeterminacy in what values variables are. Imperative programming did tend to make me a sloppier programmer, I think, and for this, I always felt a bit uncomfortable with the type of code I was writing. In Erlang, most errors that I am making are mostly silly pattern matching errors. I will admit, in this regard, just in terms of the variable issue, I feel more confident with the code that I am writing.&lt;br /&gt;&lt;br /&gt;2. I faced some challenges when I was dealing with looping over some data structure that seemed perfect for a regular loop. In these cases, given that I forced myself to pose the question in a functional way, the resulting code was more concise in the end. &lt;br /&gt;&lt;br /&gt;3. Besides minor problems that would come up, I have been consistently producing semi-complicated functions that work correctly the first time. I have not documented specifically when this has occurred. All I remember is that it happened a number of times and I was pleasantly surprised. It is a pleasant surprise because it never seemed to happen that way when working in an imperative language. In functional programming, with Erlang, there are cases where I consider what the problem is, write a little documentation to describe it, then just write it (I have not committed myself to TDD yet). Thinking functionally gives me a chance to look at the problem on a very high level, like, in terms of how the data structure is structured, the types of transformations that are applied to the structure, and what the results of functions over the data structure are. With those in mind, producing good-working functions tend to be the result.&lt;br /&gt;&lt;br /&gt;4. I will admit that I have not worked much concurrency with Erlang. Most of the work I have done has been using sequential Erlang. Concurrency is a little harder, but the times I have actually worked with it were times when I just sat down and coded something, not exactly knowing what I was coding. I wrote a short program that opens a large number of processes and then each process sends a message to each other process. There was some weird things that were occurring with it, but it works, and not being a multi-threading wizard by a long shot, I think this was really really nice.&lt;br /&gt;&lt;br /&gt;5. Pattern matching is probably one of the most useful language features next to variables not changing values (of course though, the two ideas are connected, since variables are patterns.) The type of things that I am doing with pattern matching is just utterly amazing; I use it in every program I write. The power lies in how I am able to describe large ideas through simple functions, by a matter of how the particular function accepts its input. In one tool I am writing (the one I mentioned in the prior post), I can easily categorize a cross-section of features for different parts of the execution of the tool using patterns; the approach is concise and is very clear to me. Here is an example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;when_valid(login, Form, Args) -&gt;&lt;br /&gt; Vals = erlyform_maker:form_values(Form),&lt;br /&gt; Results = yak:login_user(proplists:get_value(username, Vals),&lt;br /&gt;                                 proplists:get_value(p1, Vals)),&lt;br /&gt; case Results of&lt;br /&gt;  {error, user_not_found} -&gt;&lt;br /&gt;   {failure, "Username or password was incorrect. Try again."};&lt;br /&gt;  {atomic, SessionId} -&gt;&lt;br /&gt;   yaws_api:setcookie("yak", SessionId}&lt;br /&gt; end;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;when_valid(signup, Form, Args) -&gt;&lt;br /&gt; Vals = erlyform_maker:form_values(Form),&lt;br /&gt; Results = yak:create_user(proplists:get_value(username, Vals),&lt;br /&gt;                                  proplists:get_value(p1, Vals)),&lt;br /&gt; case Results of&lt;br /&gt;  {error, username_already_exists} -&gt;&lt;br /&gt;   {failure, "The username you selected already exists."};&lt;br /&gt;   _ -&gt;&lt;br /&gt;   ok&lt;br /&gt; end.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In the code above, I handle a case where web form data is valid. I have two such forms in this case, and they are both related to authentication. My tool goes ahead and validates the data that comes in and is able to call the right function above. I can't explain how neat this is. I wish Python had something like this.&lt;br /&gt;&lt;br /&gt;(Let me explain a design goal in this. If a user submits a form on the web, it comes to my server and my tool checks to see if the form is valid. If so, it calls the "when_valid" function. If there is no "when_valid" function, it calls a default version. The "when_valid" function just returns data. This is opposed to a normal ErlyWeb controller where you return an ErlyWeb tuple. I separated that out, since I never liked framework-level code to be mixed in such a way with this type of application logic.)&lt;br /&gt;&lt;br /&gt;6. Not worrying about OOP has helped me immensely. When I stopped thinking about OOPish things, which is one reason why I started using functional programming more, it has helped me focus on my problems more. There are a number of things that have started to go through my head on this issue. Of course, it is a bit personalized. One of the main issues is that, whenever I am working in an OOP language, I feel obligated to do things in an OOPish way and not in a way that solves the problem most simply, as well as cleanly. This is merely my way of wanting to use the best practices of the language. To me though, the best practices of a given OOP language are not really the best practices to me.&lt;br /&gt;&lt;br /&gt;The confirmation of my incremental success that I stated earlier lies in the absence of OOP. Maybe for big enterprise-y stuff it works nice. Maybe it is nice to know what a particular piece of data is, in the context of a software system. Maybe something like data encapsulation on objects really does wonders for ensuring some form of safety of implementation in big software systems. But, for the first, I am not working on enterprise-y stuff. For the second, if I need to say what something is, I put it in a tuple, and document that, for example, the data that is being returned is a tuple that begins with a specific atom. And, for the third, if I need data encapsulation, I always got the support of Erlang's module system.&lt;br /&gt;&lt;br /&gt;I could go on what *I* do not need in OOP. This is not the point. I have come to the opinion now if I am worrying myself over side concerns to suit the best practices of a language, maybe I should try another language. This is, at least, for cases where I have complete control over language choice.&lt;br /&gt;&lt;br /&gt;I do worry over Erlang standards. I lay out all my projects the OTP way. I try to focus on writing code with the principle of "just let it crash if it fails." But see, these things don't get in my way.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Anyway, I went on too long. So, I'll shush now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-7598578934257565721?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/7598578934257565721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=7598578934257565721' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/7598578934257565721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/7598578934257565721'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2007/04/some-observations.html' title='Some Observations'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-5851877116476289209</id><published>2007-03-24T14:03:00.000-07:00</published><updated>2007-03-24T14:24:59.932-07:00</updated><title type='text'>Web Forms With Erlang</title><content type='html'>I started a project that I eluded to in my previous entry. I only wrote the specification and started on some code. so it is far from complete. This is what I wrote so far as a "goal" statement:&lt;br /&gt;&lt;br /&gt;A mini-framework on top of ErlyWeb to:&lt;br /&gt;&lt;br /&gt;1. Generalize a common set of patterns when related to web form development. &lt;br /&gt;2. Siimplify the creation of forms for instant gratification.&lt;br /&gt;&lt;br /&gt;This is accomplished by:&lt;br /&gt;&lt;br /&gt;1. A general web form behaviour in Erlang, which handles generating new and edit forms as well as deleting and retrieving data for results or details.&lt;br /&gt;&lt;br /&gt;2. A specific way of creating multiple amount of forms in a unit.&lt;br /&gt;&lt;br /&gt;3. A way to quickly generate forms, which can be played with immediately.&lt;br /&gt;&lt;br /&gt;4. An HTML form generator that takes form specificiations an can genereate simple forms as something to start off with before a better design is created.&lt;br /&gt;&lt;br /&gt;5. The allowance of the system to easily adapt to new HTML designs and code.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The idea is this: I got a form of something - be it data to fill in from one or more database tables, or email to send, or whatever. The implementation makes a common set of assumptions about what is going to happen to the data. &lt;br /&gt;&lt;br /&gt;The assumptions are this:&lt;br /&gt;&lt;br /&gt;- This something will be created.&lt;br /&gt;- This something will be edited.&lt;br /&gt;- This something will be deleted.&lt;br /&gt;- This something will be retrieved.&lt;br /&gt;&lt;br /&gt;What is being modeled is the common expectations of what will be performed:&lt;br /&gt;&lt;br /&gt;- Data needs to be validated&lt;br /&gt;- If validations succeed, we need to know what to do next.&lt;br /&gt;- If the validations fail, we need to know what to do next.&lt;br /&gt;&lt;br /&gt;The system will have a sensible set of defaults, making it possible to make a form quickly, with the validations, and the form can immediately be tested (without any database code or what not.) When the form is shown to work, the details can be plugged in. (One idea that came to my head was to have the framework make a temporary table in Mnesia, so the retrieving aspect can be quickly tested.) &lt;br /&gt;&lt;br /&gt;My idea is to utilize an Erlang behaviour in this case. With a behaviour, the compiler can check if my specific forms are missing functions, and warn the developer of the missing function.&lt;br /&gt;&lt;br /&gt;The result is a framework the mixes a bit of simplicity (sort of what you get with ErlyWeb or Rails instant CRUD generators) as well as being general enough to be actually useful outside of just simple CRUD. &lt;br /&gt;&lt;br /&gt;In this process, I have started to rewrite my HTML form builder I mentioned in a prior post. There is a lack of generality in it that I need to fix.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-5851877116476289209?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/5851877116476289209/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=5851877116476289209' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/5851877116476289209'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/5851877116476289209'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2007/03/web-forms-with-erlang.html' title='Web Forms With Erlang'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-3322912999638255156</id><published>2007-03-03T18:17:00.000-08:00</published><updated>2007-03-03T19:45:13.831-08:00</updated><title type='text'>An HTML Form Builder</title><content type='html'>Here is a form builder I wrote in Erlang. I had an idea earlier, related to a project that my brother wants me to work on. I thought that it would be fruitful for us to both sit down for a few hours constructing a web site. He does not know how to code, but he can discuss aspects of what I am hacking up, so we can discuss changes while I am coding. I told him that I want to make the process of creating forms quickly, so, in a stroke of inspiration, I threw this little module together. &lt;br /&gt;&lt;br /&gt;There is little error checking involved in the code, but then, maybe, given the Erlang guidelines, this is a good thing. Look and see. Maybe you'll find it useful. I am going to update it when I need to.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The code is &lt;a href="http://www.pushon.org/erlang/form_maker.erl"&gt;here&lt;/a&gt;. An example form: &lt;a href="http://www.pushon.org/erlang/form.txt"&gt;here&lt;/a&gt;. Sample test code: &lt;a href="http://www.pushon.org/erlang/test_form_maker.erl"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;UPDATE: This little sample code makes me extremely happy, because I was able to have a very vague idea of what I wanted, and I was able to translate those ideas into working code in a reasonable amount of time. I think I can attribute this to functional programming and pattern matching. My next step (er, tomorrow :) ) Is to make a web page to generate forms, with interest in accomplishing what I want to do when my brother and I sit down and get some code working for our app.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-3322912999638255156?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/3322912999638255156/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=3322912999638255156' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/3322912999638255156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/3322912999638255156'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2007/03/html-form-builder.html' title='An HTML Form Builder'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-6673425454801562629</id><published>2007-03-03T11:45:00.000-08:00</published><updated>2007-03-03T12:02:48.551-08:00</updated><title type='text'>An Erlang Project</title><content type='html'>I figured that I am maintaining a focus on a particular language and am going to progress in a particular project for my computer science degree, I might as well use this space to discuss Erlang more and what I am doing in it.&lt;br /&gt;&lt;br /&gt;What I am focusing on, for my final-year project is a study of the use of Erlang in the context of web applications. I am evaluating what interesting things that are in Erlang that can be utilized in the context of web programming. For example, is the language robust enough for general web programming? Or, where can we benefit, either directly or indirectly from Erlang's concurrency model?&lt;br /&gt;&lt;br /&gt;I am writing two small applications for this. The first is a semi-re-implementation of the Java Pet Store example. The second is a simple instant message server. Both intend to demonstrate the use, for example, of higher-order programming in the context of a real example. In the second example, I hope to demonstrate the usefulness of Erlang as a very good concurrent language with its efficient process model. Can Erlang demonstrate the idea that we can write things like instant message servers (particularly for the web) without the mental overhead of dealing with the problems around multi-threading? I admit that I am not good in multi-threading, but from what I coded up so far, I am so excited of what possibilities that can be done with Erlang.&lt;br /&gt;&lt;br /&gt;I will, for sure, be utilizing ErlyWeb, and plan to write a couple of big tutorials when I am finished with my applications (along with the academic paper I will write.)&lt;br /&gt;&lt;br /&gt;I am going to post something up here occasionally of whatever activity that is happening in my little world; hopefully people will be interested. (hehehehe)&lt;br /&gt;&lt;br /&gt;... also, check out Joe Armstrong's new Prgamatic Programmer book, Programming Erlang: http://pragmaticprogrammer.com/titles/jaerlang/index.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-6673425454801562629?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/6673425454801562629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=6673425454801562629' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/6673425454801562629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/6673425454801562629'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2007/03/erlang-project.html' title='An Erlang Project'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-2820018271907025167</id><published>2006-12-21T11:13:00.000-08:00</published><updated>2006-12-21T11:15:35.773-08:00</updated><title type='text'>People are actually reading this?</title><content type='html'>Hmm, I never drew any popularity to any of my prior silly weblog attempts until now.It must be the tutorial that I put up. :D&lt;br /&gt;&lt;br /&gt;Thanks for all the comments thus far.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-2820018271907025167?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/2820018271907025167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=2820018271907025167' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/2820018271907025167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/2820018271907025167'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2006/12/people-are-actually-reading-this.html' title='People are actually reading this?'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-7304148267261845017</id><published>2006-12-19T09:43:00.000-08:00</published><updated>2006-12-19T10:03:10.689-08:00</updated><title type='text'>OO That Looks Like Procedural Programs</title><content type='html'>I wrote this to a couple of people on a private mailing list I am on:&lt;br /&gt;&lt;br /&gt;"OO has never lived up to the potential for me, for precisely the&lt;br /&gt;reason that most 'OO type' work I do (mostly via web apps) all tends to look like&lt;br /&gt;procedural applications just with OO constructs around it. Get rid of&lt;br /&gt;the OO constructs, and you pretty much got the same program, just&lt;br /&gt;without the OO overhead. So why should I bother with OO? This is one&lt;br /&gt;of the motivations that led me to functional programming. All the good&lt;br /&gt;practices that is present OO still stand (like hiding implementation&lt;br /&gt;from interface, the use of opaque values (related with the first one),&lt;br /&gt;polymorphic functions), but it just doesn't think it is necessary to&lt;br /&gt;bind data and bahavior together. Higher-order functions seem, right&lt;br /&gt;now, to make sense more, for reusability purposes now than through&lt;br /&gt;inheritance (ask my opinion on it after I developed some non-trivial&lt;br /&gt;stuff with functional languages :))"&lt;br /&gt;&lt;br /&gt;I worked in Rails and I played with Python a lot in these areas. My belief stems from this change in perspective:&lt;br /&gt;&lt;br /&gt;Objects in Python are glorified dictionaries, or dictionaries with OO logic. If inheritance is necessary, then the OO logic is useful. But, eh ... I don't use inheritance. At most, I use tables to inherit similarities, using joins to accomplish that type of goal. I don't know what other people do, but I never used inheritance in such a grand way to actually see a use for it.&lt;br /&gt;&lt;br /&gt;So, looking at something like ErlyDB, and its simple use of tuples, confirmed my point. I just got lazy a little. &lt;br /&gt;&lt;br /&gt;The question is: is there anything special when it comes to merging data and functions together. For what I do, I just can't see it.&lt;br /&gt;&lt;br /&gt;I said in the first tutorial that ErlyWeb (+ erlhive, but I haven't had a chance to look at that yet) is a Rails killer. Let me elaborate on that. It might not be flush with so many features as Rails does, but the constructs are much more simpler in ErlyWeb. The thing is that ErlyWeb is not this big opaque library of magic tricks; it doesn't need to be, no matter how many "opinions" are shoved into it.&lt;br /&gt;&lt;br /&gt;But I think this pretty much reflects not so much the capabilties of a language, but the opinion of the language community. Where Rails says "you are stuck with the whole methodology that Rails has to offer", ErlyWeb should say "here is a few interesting tools to get you moving - other than that, everything is pretty much intuitive after that" This is why I think it could draw people to Erlang. I like that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-7304148267261845017?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/7304148267261845017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=7304148267261845017' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/7304148267261845017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/7304148267261845017'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2006/12/oo-that-looks-like-procedural-programs.html' title='OO That Looks Like Procedural Programs'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-6645243810760368757</id><published>2006-12-11T14:23:00.000-08:00</published><updated>2006-12-12T10:55:57.436-08:00</updated><title type='text'>ErlyWeb Tutorial Part 2</title><content type='html'>I have been looking forward to getting back to adding to this tutorial, but I have not had the chance the past few days. Now that I have a little time, I can jump in and finish the tutorial. What this part of the tutorial will address is the edit functionality for our blog application. Taking a hint from the CRUD functions that is in ErlyWeb, I will do something similar. &lt;br /&gt;&lt;br /&gt;(Tip for Erlang newbies: use m(module_name) to find out about what functions are exported from a module. Very handy feature!)&lt;br /&gt;&lt;br /&gt;ErlyDB looks like a smart fellow, because it knows that, despite using basic tuples, can figure out if the data is in the database or not. It probably isn't anything special, and Yariv will probably agree (since he wrote it), but it is interesting nonetheless.&lt;br /&gt;&lt;br /&gt;I said this for a reason. We can similify our code, transforming the functionality in new_post/1 into something that calls a generic function, new_or_edit/2, which will also handle post editing. This is possible because ErlyDB saves records with same function.&lt;br /&gt;&lt;br /&gt;In your entries_controller.erl file, get rid of the new_post/1 function, and then stick this in:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;new_post(Vals) -&gt;&lt;br /&gt; Entry = entries:set_fields_from_strs(entries:new(), Vals),&lt;br /&gt; new_or_edit(Entry, Vals).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We exported most of the logic that was in new_post/1 into new_or_edit/2. Put the new_or_edit/2 function in:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;new_or_edit(Entry, Vals) -&gt;&lt;br /&gt; EntryV = entries:set_fields_from_strs(Entry, Vals),&lt;br /&gt; Errors = helpers:validate(entries_validate, entries, EntryV),&lt;br /&gt; &lt;br /&gt; case Errors of&lt;br /&gt;  ok -&gt;&lt;br /&gt;   entries:save(EntryV),&lt;br /&gt;   {ok, EntryV};&lt;br /&gt;  _ -&gt;&lt;br /&gt;   {Errors, EntryV}&lt;br /&gt; end.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It is a fact that this function applies to both creating a new entry and editing an entry. This is true because what we are going to show now, with the edit functionality. Put this code in:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;%% Edit functions.&lt;br /&gt;&lt;br /&gt;edit(A, Id) -&gt;&lt;br /&gt; case yaws_arg:method(A) of&lt;br /&gt;  'GET' -&gt;&lt;br /&gt;   {data, {"", edit_get(Id)}};&lt;br /&gt;  'POST' -&gt;&lt;br /&gt;   Vals = yaws_api:parse_post(A),&lt;br /&gt;   {Errors, Entry} = edit_post(Vals, Id),&lt;br /&gt;   case Errors of&lt;br /&gt;    ok -&gt;&lt;br /&gt;     {ewr, entries, index};&lt;br /&gt;    _ -&gt;&lt;br /&gt;     {data, {Errors, Entry}}&lt;br /&gt;   end&lt;br /&gt; end.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;edit_get(Id) -&gt;&lt;br /&gt; Entry = entries:find_id(Id),&lt;br /&gt; Entry.&lt;br /&gt;&lt;br /&gt;edit_post(Vals, Id) -&gt;&lt;br /&gt; Entry = entries:find_id(Id),&lt;br /&gt; new_or_edit(Entry, Vals).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;WAIT A MINUTE! We are doing almost the same thing that is being done in our new function! Time to do some parameterization, to get rid of that look of cut-and-paste yuckiness. Look at where the differences are ... The function that is called to get an entry in "GET" and possibly, the space where we do a redirect. Let's add a library function! But, for you neophytes to functional programming ... we are going to use higher-order functions.&lt;br /&gt;&lt;br /&gt;Here is the generic function:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;form_process(A,&lt;br /&gt;             GetAction, &lt;br /&gt;      ModelAction,&lt;br /&gt;      PostSuccessAction, &lt;br /&gt;      PostFailureAction) -&gt;&lt;br /&gt; case yaws_arg:method(A) of&lt;br /&gt;  'GET' -&gt;&lt;br /&gt;   GetAction();&lt;br /&gt;  'POST' -&gt;&lt;br /&gt;   Vals = yaws_api:parse_post(A),&lt;br /&gt;   {Errors, Record} = ModelAction(Vals),&lt;br /&gt;   case Errors of&lt;br /&gt;    ok -&gt;&lt;br /&gt;     PostSuccessAction();&lt;br /&gt;    _ -&gt;&lt;br /&gt;     PostFailureAction(Errors, Record)&lt;br /&gt;   end&lt;br /&gt; end.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Essentially, the form_process/5 function is just a generalization of what we have been doing before. Except, this time, we replaced the specific places with function calls - to functions we will define in our new/1 function.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;new(A) -&gt;&lt;br /&gt; GetAction = fun() -&gt;&lt;br /&gt;   {data, {[], new_get()}} end,&lt;br /&gt; ModelAction = fun(Vals) -&gt;&lt;br /&gt;   new_post(Vals) end,&lt;br /&gt; PostSuccessAction = fun() -&gt;&lt;br /&gt;    {ewr, entries, index} end,&lt;br /&gt; PostFailureAction = fun(Errors, Entry) -&gt;&lt;br /&gt;    {data, {Errors, Entry}} end,&lt;br /&gt; &lt;br /&gt; form_process(A, GetAction, ModelAction, PostSuccessAction, PostFailureAction).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and then edit/1: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;edit(A, Id) -&gt;&lt;br /&gt; GetAction = fun() -&gt;&lt;br /&gt;   {data, {[], edit_get(Id)}} end,&lt;br /&gt; ModelAction = fun(Vals) -&gt;&lt;br /&gt;   edit_post(Vals, Id) end,&lt;br /&gt; PostSuccessAction = fun() -&gt;&lt;br /&gt;   {ewr, entries, index} end,&lt;br /&gt; PostFailureAction = fun(Errors, Entry) -&gt;&lt;br /&gt;   {data, {Errors, Entry}} end,&lt;br /&gt; &lt;br /&gt; form_process(A, GetAction, ModelAction, PostSuccessAction, PostFailureAction).&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(NOTE! For some weird reason, when I am running new/1 through the browser, and hit submit, it takes a bit too long to load. Is this a bug in my code? edit/1, though, works like a charm. Go figure.)&lt;br /&gt;&lt;br /&gt;So, we developed a pattern using common code and, more importantly, &lt;i&gt;a common convention&lt;/i&gt;, meaning a common set of expectations. There is nothing grandiose about the convention, and yes, you can completely ignore it. The lines of code in my function is not my concern, but whether or not I can make the code more &lt;i&gt;declarative&lt;/i&gt;, in the sense that I say "do this in this location, do this in this other location." But, I am thinking that the code there can be tightened up even more.&lt;br /&gt;&lt;br /&gt;In your entries_view.erl file, add these functions:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;new(Data) -&gt;&lt;br /&gt; entry_form:display_form(Data, "../new", "").&lt;br /&gt;&lt;br /&gt;edit(Data) -&gt;&lt;br /&gt; entry_form:display_form(Data, "../edit", &lt;br /&gt;      integer_to_list(entries:id(element(2,Data)))).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Yep, we are using the same form for editing and displaying. However, we made a change. I needed to make the action in the form generic. So the new parameters represent the url to go to. I moved the form to its own module, in a file called "entry_form.et" - I am going for some sense of template organization, by putting one page per ErlTL file. But, I originally put it in "entries_show.et". Note the changes I made with the parameters. Here is the new lines:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;%@ display_form(Items, GoTo, Id) %&gt;&lt;br /&gt;&lt;br /&gt;and&lt;br /&gt;&lt;br /&gt;&lt; form action="&lt;% GoTo %&gt;/&lt;% Id %&gt;" method="POST" &gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We also want to make a small addition, by adding a "view" function. This one is quite simple. In your entries_controller.erl file, add this function:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;view(A, Id) -&gt;&lt;br /&gt;    Entry = get_entry(Id),&lt;br /&gt;    {data, Entry}.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In your entries_view.erl file, add this function:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;view(Data) -&gt;&lt;br /&gt;    entry_view:view(Data).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Add a file called "entry_view.et" for the view, and add this to the file:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;%@ view(Data) %&gt;&lt;br /&gt;&lt; b&gt;&lt;% entries:title(Data) %&gt;&lt; /b&gt;&lt;br /&gt;&lt; br /&gt;&lt; br /&gt;&lt;br /&gt;&lt;% entries:body(Data) %&gt;&lt;br /&gt;&lt; br /&gt;&lt;br/&gt;&lt;br /&gt;&lt; i&gt;by: &lt;% entries:author(Data) %&gt;&lt; /i&gt;&lt;br /&gt;&lt; br /&gt;&lt; br /&gt;&lt;br /&gt;&lt;% erlyweb_html:a(["../edit", integer_to_list(entries:id(Data))], "Edit Entry") %&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Maybe, also, add a link to the view in your entries_show.et file.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;% erlyweb_html:a(["view", integer_to_list(entries:id(Entry))], "view") %&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Put it in your entry/1 function in the template.&lt;br /&gt;&lt;br /&gt;Also, maybe you can finish off the show_entries/1 function in the same template file with a link to the new entry form. I'm lazy - you do it yourself. :)&lt;br /&gt;&lt;br /&gt;Now, go to Yaws, type "start:boot()" and go to your index page. All of the elements should be visible. Is it? Any problems? If there is, this is a good time to learn what Erlang is saying to you. :P Now, if there is a problem in the tutorial, do contact me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-6645243810760368757?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/6645243810760368757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=6645243810760368757' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/6645243810760368757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/6645243810760368757'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2006/12/erlyweb-tutorial-part-2.html' title='ErlyWeb Tutorial Part 2'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-73092984370704882</id><published>2006-12-04T13:41:00.000-08:00</published><updated>2006-12-05T13:04:56.121-08:00</updated><title type='text'>ErlyWeb - Blog Tutorial</title><content type='html'>UPDATE: I am going to expand this tutorial a bit, later on, but, as of now, the tutorial can stand on its own. I only included a discussion on displaying blog entries and creating new entries. Later, I will be adding a discussion on adding an edit page and adding delete functionality.&lt;br /&gt;&lt;br /&gt;A week ago, I started to play with Erlang. I wanted to look into web development with functional languages, so I invested time in a certain toolkit called &lt;a href="http://www.erlyweb.org/"&gt;ErlyWeb&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here is a small tutorial of creating a simple weblog application in it. I am assuming you went through the musician tutorial, which explains in detail, getting Erlang, ErlyWeb, MySQL, blah blah blah. This tutorial is just a rough sketch of discoveries I made while using it.&lt;br /&gt;&lt;br /&gt;(I typed this really quickly. So, if you try this, you need to fix all the HTML ... Blogger was rendering the HTML and I am too tired to find out why. So, I merely stuck a space after each &lt; for now. I'll fix later.)&lt;br /&gt;&lt;br /&gt;To start, we need to create an application like such, in the erl shell:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;erlyweb:create_app("blog", "/path/to/apps").&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then, we create a table in MySQL, like such:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;create table entries (&lt;br /&gt;  id integer auto_increment primary key,&lt;br /&gt;  title varchar(100),&lt;br /&gt;  body text,&lt;br /&gt;  author varchar(100)&lt;br /&gt;);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We create an entries component:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;erlyweb:create_component("entries", "/path/to/apps/blog").&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;While here, create a file called "entries_validate.erl" in your "src" directory in your app directory.&lt;br /&gt;&lt;br /&gt;I created a small file that I put on the root of the blog directory which will start up a MySQL connection in ErlyDB as well as compile the whole app. I put this file on the root of the blog directory (and will reference to this place in other places in the tutorial.) Here is the file (edit where necessary):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-module(start).&lt;br /&gt;-export([boot/0, boot/1]).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;boot() -&gt;&lt;br /&gt;boot(true).&lt;br /&gt;boot(false) -&gt;&lt;br /&gt;compile();&lt;br /&gt;boot(true) -&gt;&lt;br /&gt;mysql_start(),&lt;br /&gt;compile().&lt;br /&gt;&lt;br /&gt;mysql_start() -&gt;&lt;br /&gt;erlydb:start(mysql, [{hostname, "localhost"},&lt;br /&gt;      {username, "username"},&lt;br /&gt;      {password, "password"},&lt;br /&gt;      {database, "blog"}]).&lt;br /&gt;&lt;br /&gt;compile() -&gt;&lt;br /&gt;erlyweb:compile("/path/to/app/blog",&lt;br /&gt;  [{erlydb_driver, mysql}]).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This comes in handy, if you restart yaws, for example - you don't need to type in the connection function every time.&lt;br /&gt;&lt;br /&gt;Edit your yaws.conf file:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt; server junk &gt;&lt;br /&gt;  port = 8000&lt;br /&gt;  listen = 127.0.0.1&lt;br /&gt;  docroot = /path/to/blog/www&lt;br /&gt;  appmods = &lt;"/blog", erlyweb&gt;&lt;br /&gt;  &lt;opaque&gt;&lt;br /&gt;  appname = blog&lt;br /&gt;  &lt;/opaque&gt;&lt;br /&gt;&lt; /server &gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then, start yaws:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;yaws -i&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cruise over to your localhost:8000/blog/entries page, and enter a few new entries, for some starter data.&lt;br /&gt;&lt;br /&gt;In your src/components/entries_controller.erl file, comment out the erlyweb_magic line. We are turning off the stuff we were using just before.&lt;br /&gt;&lt;br /&gt;Now, we will start with the front page. We will want to create an index function that merely shows all the entries on the screen. In the entries_controller.erl file, enter this function in:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;index(A) -&gt;&lt;br /&gt;   Entries = entries:find(),&lt;br /&gt;   {data, Entries}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and put in your export line:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-export([index/1]).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What that function is merely saying is that it should get all the entries in the the entries table, and send the entries off to the view function.&lt;br /&gt;&lt;br /&gt;Open up entries_view.erl, and enter this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;index(Data) -&gt;&lt;br /&gt;   entries_show:show_entries(Data).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and in your export line:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-export([index/1]).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In our view function, we are getting the data ("Entries") from the controller function, and now we are merely passing the data to the display function. Make a file called "entries_show.et" in the src/components directory and enter this code in:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;%@ show_entries(Entries) %&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;% [entry(E) || E &lt;- Entries] %&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;&lt;%@ entry(Entry) %&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;% helpers:value(entries:title(Entry)) %&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;% helpers:value(entries:body(Entry)) %&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt; by: &lt;% helpers:value(entries:author(Entry)) %&gt; &lt;/i&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We are almost done. In the current version of ErlyWeb, I was having problems when the value of a particular field, like the output from entries:title(), would return undefined, and it would crash the yaws process (of course, it is not going to crash the server!) So, I created a small set of functions in a "helpers" module. Make this file in your src directory, and add this code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-module(helpers).&lt;br /&gt;-export([value/1]).&lt;br /&gt;&lt;br /&gt;value(Val) -&gt;&lt;br /&gt;case Val of&lt;br /&gt; undefined -&gt;&lt;br /&gt;  "";&lt;br /&gt; _ -&gt;&lt;br /&gt;  Val&lt;br /&gt;end.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We'll use this little code snippet for now.&lt;br /&gt;&lt;br /&gt;Now, go to the root of the blog directory (you can use the cd() function in yaws, so you don't have to go back to your shell) and type:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;start:boot().&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Hopefully, everything will be fine. It will finish up with a tuple starting with "ok" at the beginning.&lt;br /&gt;&lt;br /&gt;Go to your page, http://www.localhost:8000/blog/entries and you will hopefully see, in all its glory, the records you entered in before.&lt;br /&gt;&lt;br /&gt;Now, we are going to expand the helpers module. Here is the complete helpers module file:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-module(helpers).&lt;br /&gt;-export([value/1, validate/3]).&lt;br /&gt;&lt;br /&gt;value(Val) -&gt;&lt;br /&gt;case Val of&lt;br /&gt; undefined -&gt;&lt;br /&gt;  "";&lt;br /&gt; _ -&gt;&lt;br /&gt;  Val&lt;br /&gt;end.&lt;br /&gt;&lt;br /&gt;validate(ValidatorModule, Model, Item) -&gt;&lt;br /&gt;Fields = Model:use_fields(),&lt;br /&gt;Results = [ValidatorModule:Field(Model:Field(Item)) || Field &lt;- Fields],  &lt;br /&gt;Errors = [Error || Error &lt;- Results,element(1, Error) == error],    &lt;br /&gt;case Errors of   [] -&gt;&lt;br /&gt;  ok;&lt;br /&gt; _ -&gt;&lt;br /&gt;     Errors&lt;br /&gt;end.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;  &lt;br /&gt;We added a validation function here. We are going to add a simple form to the mix; something to add new entries.&lt;br /&gt;&lt;br /&gt;Back in the entries_controller.erl file, enter in this code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;new(A) -&gt;&lt;br /&gt;case yaws_arg:method(A) of&lt;br /&gt; 'GET' -&gt;&lt;br /&gt;  {data, {[], new_get()}};&lt;br /&gt; 'POST' -&gt;&lt;br /&gt;  Vals = yaws_api:parse_post(A),&lt;br /&gt;  {Errors, Entry} = new_post(Vals),&lt;br /&gt;  case Errors of&lt;br /&gt;   ok -&gt;&lt;br /&gt;    {ewr, index};&lt;br /&gt;   _ -&gt;&lt;br /&gt;    {data, {Errors, Entry}}&lt;br /&gt;  end&lt;br /&gt;   end.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;new_get() -&gt;&lt;br /&gt;   Entry = entries:new(),&lt;br /&gt;   Entry.&lt;br /&gt;&lt;br /&gt;new_post(Vals) -&gt;&lt;br /&gt;Entry = entries:set_fields_from_strs(entries:new(), Vals),&lt;br /&gt;Errors = helpers:validate(entries_validate, entries, Entry),&lt;br /&gt;case Errors of&lt;br /&gt; ok -&gt;&lt;br /&gt;  entries:save(Entry),&lt;br /&gt;  {ok, Entry};&lt;br /&gt; _ -&gt;&lt;br /&gt;  {Errors, Entry}&lt;br /&gt;end.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and our export line:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-export([index/1, new/1, new_get/0, new_post/1]).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(We could make the new_get/0 and new_post/1 functions private to the web, but we'll consider this later.)&lt;br /&gt;&lt;br /&gt;The new/1 function is the function that is exposed to the web. I split the logic of supplying a new form and creating a new entry because it will prove easier to unit test instead of mucking around with making a value to submit into new/1.&lt;br /&gt;&lt;br /&gt;For GET in new/1, we merely drop in a new entries tuple into the form:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;'GET' -&gt;&lt;br /&gt;   {data, {[], new_get()}};&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;new_get() -&gt;&lt;br /&gt;   Entry = entries:new(),&lt;br /&gt;   Entry.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I return from new/1 in the 'GET' case with a "data" tuple, with a 2-tuple. The first item in the 2-tuple is an empty list - for the 'POST' part, we would use that location in the 2-tuple for errors. The second location is the entry we are considering.&lt;br /&gt;&lt;br /&gt;For 'POST':&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; 'POST' -&gt;&lt;br /&gt;  Vals = yaws_api:parse_post(A),&lt;br /&gt;  {Errors, Entry} = new_post(Vals),&lt;br /&gt;  case Errors of&lt;br /&gt;   ok -&gt;&lt;br /&gt;    {ewr, index};&lt;br /&gt;   _ -&gt;&lt;br /&gt;    {data, {Errors, Entry}}&lt;br /&gt;  end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here, we get all the values from the post payload, and then run the new_post/1 function. If new_post/1 returns {ok, Entry}, then it will redirect to the index page. If not, it will show the form again, and display the errors, and fill in the form elements that are already filled in. Here, we can see now the corollary between the return value in 'GET':&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;{data, {Errors, Entry}}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;"Errors" contains a list of tuples containing our error messages. The Entry variable contains an ErlyDB tuple that we received from new_post/1. Let's look at new_post/1.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;new_post(Vals) -&gt;&lt;br /&gt;Entry = entries:set_fields_from_strs(entries:new(), Vals),&lt;br /&gt;Errors = helpers:validate(entries_validate, entries, Entry),&lt;br /&gt;case Errors of&lt;br /&gt; ok -&gt;&lt;br /&gt;  entries:save(Entry),&lt;br /&gt;  {ok, Entry};&lt;br /&gt; _ -&gt;&lt;br /&gt;  {Errors, Entry}&lt;br /&gt;end.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here, when we get the values from the post payload, we convert the values into an entries tuple. Then, we submit into our validate/3 function (from before) with any errors. If validate/3 returns ok, then there were no errors. Otherwise, we will return the errors.&lt;br /&gt;&lt;br /&gt;validate/3 takes the name of your validation module, your model module and the actual data tuple.&lt;br /&gt;&lt;br /&gt;I said to create an entries_validate.erl file. Let's create that.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-module(entries_validate).&lt;br /&gt;-export([title/1, body/1, author/1]).&lt;br /&gt;&lt;br /&gt;title(undefined) -&gt;&lt;br /&gt;{error, title, "The title field is blank."};&lt;br /&gt;title(_) -&gt;&lt;br /&gt; ok.&lt;br /&gt;&lt;br /&gt;body(undefined) -&gt;&lt;br /&gt;{error, body, "The body field is blank."};&lt;br /&gt;body(_) -&gt;&lt;br /&gt;ok.&lt;br /&gt;&lt;br /&gt;author(undefined) -&gt;&lt;br /&gt;{error, author, "The author field is blank."};&lt;br /&gt;author(_) -&gt;&lt;br /&gt;ok.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In entries.erl, put this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-export([use_fields/0]).&lt;br /&gt;&lt;br /&gt;use_fields() -&gt;&lt;br /&gt;[title, body, author].&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The validate/3 function loops through the list of names from use_fields() and checks the data in the model tuple, using the functions you provide in entries_validate.erl.&lt;br /&gt;&lt;br /&gt;(I say, isn't validation extremely simple in ErlyWeb? A tiny function to get rid of boilerplate code, and a small convention on how to present the data, and that's it!)&lt;br /&gt;&lt;br /&gt;Once you got validation in place, enter this into your entries_view.erl file:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;new(Data) -&gt;&lt;br /&gt;entries_show:display_form(Data).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and the export line:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-export([index/1, new/1]).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and now, the form, which we will stick also at the bottom of entries_show.et:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;%@ display_form(Items) %&gt;&lt;br /&gt;&lt;%? {Errors, Data} = Items %&gt;&lt;br /&gt;&lt;% helpers_html:show_errors(Errors) %&gt;&lt;br /&gt;&lt;br /&gt;&lt; form action="new" method="post"&gt;&lt;br /&gt;&lt; table&gt;&lt;br /&gt;&lt; tbody&gt;&lt; tr&gt;&lt; td valign="top"&gt;Title:&lt; /td&gt;&lt;br /&gt;&lt; td&gt;&lt;br /&gt;&lt;% erlyweb_html:input("title", text_field, undefined, helpers:value(entries:title(Data))) %&gt;&lt;br /&gt;&lt; /td&gt;&lt;br /&gt;&lt; /tr&gt;&lt;br /&gt;&lt;br /&gt;&lt; tr&gt;&lt; td valign="top"&gt;Body:&lt; /td&gt;&lt;br /&gt;&lt; td&gt;&lt;br /&gt;&lt;% erlyweb_html:input("body", text_area, undefined, helpers:value(entries:body(Data))) %&gt;&lt;br /&gt;&lt; /td&gt;&lt;br /&gt;&lt; /tr&gt;&lt;br /&gt;&lt;br /&gt;&lt; tr&gt;&lt;td valign="top"&gt;Author:&lt; /td&gt;&lt;br /&gt;&lt; td&gt;&lt;% erlyweb_html:input("author", text_field, undefined, helpers:value(entries:author(Data))) %&gt;&lt; /td&gt;&lt;br /&gt;&lt; /tr&gt;&lt;br /&gt;&lt; tr&gt;&lt;td&gt;&lt; input value="Submit" type="submit"&gt;&lt; /td&gt;&lt; /tr&gt;&lt;br /&gt;&lt; /tbody&gt;&lt; /table&gt;&lt;br /&gt;&lt; /form&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Hopefully, all this code is self-evident.&lt;br /&gt;&lt;br /&gt;Before we finish, one more thing. I added a small module in ErlTL called helpers_html.et in my src/ directory:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;%@ show_errors(Errors) %&gt;&lt;br /&gt;&lt; ul&gt;&lt;br /&gt;&lt;% [error(E) || E &lt;- Errors] %&gt;&lt;br /&gt;&lt; /ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;%@ error(Error) %&gt;&lt;br /&gt;&lt; li&gt;&lt;% element(3, Error) %&gt;&lt; /li&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This will show us our errors, if we make a mistake in our form.&lt;br /&gt;&lt;br /&gt;Now, back in yaws, type in:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;start:boot().&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and go back to your browser and go to localhost:8000/entries/new.&lt;br /&gt;&lt;br /&gt;Make a mistake. Hit submit. Do you see the errors pop up? Fill in the form correctly. Does it go to the index page properly? If so, we have a simple blog app working.&lt;br /&gt;&lt;br /&gt;Of course, I totally ignored editing posts in this tutorial. Maybe I will add this later. But, I hope you are seeing what I am seeing. ErlyWeb has INCREDIBLE POTENTIAL, since it avoids a lot of complexity. Any gaps we found thus far were easily plugged in. Even though ErlyWeb is new, this, so far, blows Rails out of the water in terms of brevity. Of course, it took me longer to figure this all out how to do this, since the docs are not up to par yet. Hopefully, this can be fixed soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-73092984370704882?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/73092984370704882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=73092984370704882' title='162 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/73092984370704882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/73092984370704882'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2006/12/erlyweb-blog-tutorial.html' title='ErlyWeb - Blog Tutorial'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>162</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-1635252836947494027</id><published>2006-11-14T19:13:00.000-08:00</published><updated>2006-11-14T19:54:38.048-08:00</updated><title type='text'>Haskell Stacks : Two Different Ways</title><content type='html'>I am starting to attempt to understand how Haskell can persist functions sans the variables. You can do it with lists, already. There are plenty of functions that demonstrate the concept. But I want to expand further. I want to try implementing a stack with a list, and then do it with a recursive type. This is what I have for the first one:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;putAtEnd [] item = [item]&lt;br /&gt;putAtEnd (x:xs) item = x : putAtEnd xs item&lt;br /&gt;&lt;br /&gt;push lst item = putAtEnd lst item&lt;br /&gt;-- or&lt;br /&gt;-- push lst item = reverse (item : (reverse lst))&lt;br /&gt;&lt;br /&gt;pop lst = pop_ lst ((length lst) - 1)&lt;br /&gt;&lt;br /&gt;pop_ _ 0 = []&lt;br /&gt;pop_ (x:xs) len = x : pop_ xs (len - 1)&lt;br /&gt;&lt;br /&gt;-- or&lt;br /&gt;-- pop lst = reverse (tail (reverse lst))&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I thought the reverse function was neat, but seemingly costly. But, from the Prelude:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;reverse :: [a] -&gt; [a]&lt;br /&gt;reverse = foldl (flip (:)) []&lt;br /&gt;&lt;br /&gt;flip f x y = f y x&lt;br /&gt;&lt;br /&gt;foldl f z [] = z&lt;br /&gt;foldl f z (x : xs) = foldl f (f z x) xs&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We can see a really slick way of doing reverses. "reverse" is merely a function curry of a foldl waiting for the last parameter. Let's see if it is costly:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;reverse [1,2,3,4]&lt;br /&gt; -&gt; foldl (flip (:)) [] [1,2,3,4]&lt;br /&gt;    -&gt; foldl (flip (:)) (flip [] 1) [2,3,4]&lt;br /&gt;    -&gt; foldl (flip (:)) (1 : []) [2,3,4]&lt;br /&gt;          -&gt; foldl (flip (:)) (flip [1] 2) [3,4]&lt;br /&gt;          -&gt; foldl (flip (:)) (2 : [1]) [3,4]&lt;br /&gt;                -&gt; foldl (flip (:)) (flip [2,1] 3) [4]&lt;br /&gt;                -&gt; foldl (flip (:)) (3 : [2,1]) [4]&lt;br /&gt;                      -&gt; foldl (flip (:)) (flip 4 : [3,2,1]) []&lt;br /&gt;                      -&gt; foldl (flip (:)) [4,3,2,1] []&lt;br /&gt;-&gt; [4,3,2,1]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So, the ones with the same indentation are the same, except the second line is the flip function evaluated. It is what I expected, though. It takes O(n) (?) time (there are two operations on the data: one operation to flip, and another operation to add to the new list. So, maybe it is O(2n)? I forget my algorithm lessons.) It seems though, that the original implementation I provided performs the same though. Maybe expressing it via reverse then is easier.&lt;br /&gt;&lt;br /&gt;Lists are, still probably still efficiently implemented, and those operations I am doing are turned into an iteration (tail-call recursion), plus some other magic I don't know about. I have to think of a nifty way of handling it faster though.&lt;br /&gt;&lt;br /&gt;Anyway, the other idea I had was to make a stack a recursive data type:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;data Stack n m = Item m | StackFrame ((Stack n) (Item m))&lt;br /&gt;&lt;br /&gt;-- so ... &lt;br /&gt;&lt;br /&gt;(StackFrame (StackFrame (Item 1) (Item 2)) (Item 3))&lt;br /&gt;&lt;br /&gt;-- looks like&lt;br /&gt;&lt;br /&gt;-- 3&lt;br /&gt;-----&lt;br /&gt;-- 2&lt;br /&gt;-----&lt;br /&gt;-- 1&lt;br /&gt;-----&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What a wacky idea. I have to think about this one, and read some common examples on this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-1635252836947494027?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/1635252836947494027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=1635252836947494027' title='29 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/1635252836947494027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/1635252836947494027'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2006/11/haskell-stacks-two-different-ways.html' title='Haskell Stacks : Two Different Ways'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>29</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-6575095183792190513</id><published>2006-11-13T12:49:00.000-08:00</published><updated>2006-11-13T12:58:42.852-08:00</updated><title type='text'>Haskell Golf Scores</title><content type='html'>I am tutoring someone in Java. We did an example program of summing up the golf scores of a number of people. I was interested in showing him some MVC design principles, as it will be useful for his end-of-year project.&lt;br /&gt;&lt;br /&gt;I decided to improve my understanding of Haskell today, by reimplementing it in Haskell. It lacks MVCishness, but it's still nice. I also couldn't find a function to convert from strings to integers, so I implemented one quickly using a number-&gt;int function. It is not perfect, since it does conversions to hex digits, but it is a start.&lt;br /&gt;&lt;br /&gt;Can I improve on it? Please do comment. ;)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;module GolfScore where&lt;br /&gt;&lt;br /&gt;import Data.Char&lt;br /&gt;&lt;br /&gt;toNumber str =&lt;br /&gt; let slen = length str&lt;br /&gt; in&lt;br /&gt;   toNum_ str ((length str) - 1) 0&lt;br /&gt;&lt;br /&gt;toNum_ :: [Char] -&gt; Int -&gt; Int -&gt; Int&lt;br /&gt;toNum_ str (-1) val = val&lt;br /&gt;&lt;br /&gt;toNum_ str count val =&lt;br /&gt; let currVal = (str !! count)&lt;br /&gt; in toNum_ str (count - 1)&lt;br /&gt;        (val + ((digitToInt currVal) * (10 ^ (((length str) - 1) - count))))&lt;br /&gt;&lt;br /&gt;----------&lt;br /&gt;-- main&lt;br /&gt;----------&lt;br /&gt;run count holes = run_ count holes [] []&lt;br /&gt;&lt;br /&gt;run_ 0 holes lstName lstRes = showResults (reverse lstName) (reverse lstRes)&lt;br /&gt;run_ count holes lstName lstRes =&lt;br /&gt;   do putStr "Enter name: "&lt;br /&gt;      n &lt;- getLine&lt;br /&gt;      scores &lt;- getAndAddScores holes []&lt;br /&gt;     &lt;br /&gt;      run_ (count -1) holes (n : lstName)&lt;br /&gt;               ((foldr ((+) . toNumber) 0 scores) : lstRes)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;showResults [] _ = return ()&lt;br /&gt;showResults (x:xs) (y : ys) =&lt;br /&gt;   do&lt;br /&gt;     putStr x&lt;br /&gt;     putStr " got a score of: "&lt;br /&gt;     print y&lt;br /&gt;     showResults xs ys   &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;getAndAddScores 0 scores = do return scores&lt;br /&gt;getAndAddScores holes scores =&lt;br /&gt;   do&lt;br /&gt;      putStr "Enter score: "&lt;br /&gt;      score &lt;- getLine&lt;br /&gt;      getAndAddScores (holes - 1) (score : scores)&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-6575095183792190513?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/6575095183792190513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=6575095183792190513' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/6575095183792190513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/6575095183792190513'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2006/11/haskell-golf-scores.html' title='Haskell Golf Scores'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32850121.post-8077013016439031380</id><published>2006-11-13T12:48:00.000-08:00</published><updated>2006-11-13T12:49:39.665-08:00</updated><title type='text'>This Weblog</title><content type='html'>I am going to post random samples of code that look interesting to me in languages I am trying out. Right now, I have to look at other programming languages that I do not completely know. It will start off with a lot of Haskell and Ada code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32850121-8077013016439031380?l=progexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://progexpr.blogspot.com/feeds/8077013016439031380/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=32850121&amp;postID=8077013016439031380' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/8077013016439031380'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32850121/posts/default/8077013016439031380'/><link rel='alternate' type='text/html' href='http://progexpr.blogspot.com/2006/11/this-weblog.html' title='This Weblog'/><author><name>a</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
