fREWdiculous!
28 Mar
I’m sorry that I’ve neglected this blog so much the past couple of weeks. I will give excuses promptly, and then I will immediately follow that with another post that you will hopefully find of value
So I was fairly sick this week and that really killed my output. It’s hard to pursue what you love when you don’t even feel alive. Turns out a lot of my friends got sick around the same time, so I image that something is going around. The irony (tragic, according to Meriam-Webster) was that last week was also when we had decided to demo our customer’s product.
And that is a great segue into what this post is about: how we do demos for our customers.
We do a loose form of agile development at my company, mostly due to the lack of much organization or planning as a whole. In general I think this is a good thing. On the project I am working on we are trying to do something closer to SCRUM. We haven’t quite mastered it yet, but we are doing iterations and demos for our customers and Neil and I meet every day to talk about progress. I am not quite organized enough at this point to keep up with a burndown chart and I keep forgetting to even do anything with the bug tracker. We are getting there nonetheless.
The point of my digression there is that we do these demos for the customers, but instead of just showing them all of our features we try to take it a step further. Features are great, but if the program is hard to use it doesn’t matter.
So what we do is set up a GoToMeeting session, I explain how we are in the project timeline to make the guys with the money happy, and then we give control to whoever will be using the feature we have completed. We give them a few directives but no directions, or at least as few as possible.
Usually they figure stuff out, but it is interesting to see what they try, and that gives us a good idea of how they think. For example, yesterday we were demoing a user system with groups. The way you would add/remove groups from a user was to drag the groups from/to a couple of grids. Seems simple enough. But the user tried to drag available groups onto the user data instead of into the user’s groups.
So when I get the chance I will make it so that that works too. The other interesting thing is the following conventional wisdom: users don’t read directions. I know that’s true, but every now and then you think, “hey, this is something that’s not perfectly obvious, so let’s put a but of text in there to make it clear.” We put something like six words in this panel, and they were at 25pt font. Guess what? Even though they were on the panel that they explained, the user didn’t read them. I may or may not leave the words there, with the knowledge that they currently just clutter up the page.
There are numerous reasons to do demos this way. They give the customers a sound mind that everything isn’t just faked. We can see what we are doing wrong from a design perspective. The customer can raise objections about possible misunderstandings we may have had. And with a user base as small as we have, we are also training them in the new application piecemeal.
And it looks like I may have to put off that other post as I have a hot date now
Have a great weekend, and stick to your requirements!
21 Mar
Furr by Blitzen Trapper
is the Album of the Week. This post (as well as 2-3 others) should have been done earlier in the week, but I was a little swamped. Sorry if you were on the edge of your seat
So Furr has definitely been my favorite album this week. I can tell because Last.fm tells me I have listened to it ELEVEN TIMES in the past 7 days. I would describe the style as somewhere between Neko Case (indie country) and Bob Dylan. I have also seen the band compared to Neil Young as well.
Their style is also slightly erratic, with songs like Fire & Fast Bullets, which brings OK Go to mind, and then Gold For Bread which is more like older rock, but with weird noises in the song at some parts. Very intriguing music.
Factoid: both Furr and God & Suicide have been on the NBC show Chuck. You may not like that show, but it definitely has lots of indie music (whatever that means.)
I dig the lyrics. The first song that caught my ear, Furr, is about the transformation from man to wolf to man. And then we have Black River Killer:
Then I went to the river for to take a swim
You know that black river water is as black as sin
And I washed myself clean as a newborn babe
And then I picked up a rock for to sharpen my blade
Favorite songs: Furr, God & Suicide, Black River Killer, Fire & Fast Bullets, Saturday Nite, Gold For Bread.
Colors: Tan and Brown.
15 Mar
Hopefully everyone reading this blog knows the function map. Map maps one array onto another with a simple function. For example, if I had a list of names at my old school and I wanted a list of emails I could do something like this:
1 2 | my @names = ('frew schmidt', 'bob barr', ); # etc... my @emails = map { s/\s+//; "$_\@letu.edu" } @names; |
I think that’s pretty great. I thought it would be cool to reinvent the wheel and implement map in Perl 6. One of them will be implemented the typical way and the other will be the Perl 6 (as far as I can tell) way.
Here’s the obvious way:
1 2 3 4 5 6 7 8 9 10 | sub map1(Code $fn, @list) { my @new_list; for @list { @new_list.push($fn($_)); } return @new_list; } map1({ $_ * 2 },[ 1,2,3,4,5 ]).perl.say; map1(sub ($f) { $f + 2 },[ 1,2,3,4,5 ]).perl.say; |
Pretty simple. We make a new list; iterate over the original list and push the value returned from the code onto the new list. But look at how much we have to think about the new list! The important part is the operation, not the list, or at least that’s what I think.
With that in mind, map round 2:
1 2 3 4 5 6 7 8 9 10 | sub map2(Code $fn, @list) { gather { for @list { take $fn($_); } } } map2({ $_ ** 2 },[ 1,2,3,4,5 ]).perl.say; map2(sub ($f) { $f ** 2 },[ 1,2,3,4,5 ]).perl.say; |
Gather/take, as mentioned previously, abstracts the idea of creating a new list.
And as for a question that Sol mentioned previously about gather and take:
… is gather / take just syntactic sugar, or is it implementing lazy evaluation, or is it even opening up the possibility of threading?
I think that gather/take is really just a pretty syntax. I think that it depends on what is inside of your gather for what is possible. You could even iterate over the contents of a file inside of a gather, in which case I am sure you couldn’t do threads. I guess lazy evaluation is theoretically possible though… But that would depend both on what is inside of the gather and what uses it.
12 Mar
I was hoping to work on the setting for Rakudo some today, but it just wasn’t happening due to my own inferiorities. I decided instead to try to read some of the setting code so that I can be less inferior in the future. I hope you enjoy learning some Perl 6!
First we’ll start with a simple one: Str.lcfirst.
1 2 3 | our Str multi method lcfirst is export { self gt '' ?? self.substr(0,1).lc ~ self.substr(1) !! "" } |
our Str multi method lcfirst is export: our means public; Str means it returns a string; multi means it can be defined with other method signatures etc; method lcfirst is the name of the method; and is export means it also becomes a function.
self gt ”: this just returns true if the current string is greater than ”, which will be true if it’s not blank.
The ?? thing is Perl 6′s tertiary, ?? !!; which is ? : in most languages. I think ?? !! is a lot easier to remember because it’s like, “is this true??then do that; !!otherwise do something else.” Thanks Larry
So if the current string isn’t empty, we do self.substr(0,1).lc ~ self.substr(1). This is the meat of the function. This basically says, starting at the beginning of the string (0) give me a 1 character string, then lowercase it, and then concatenate it with a string starting at the first character that goes all the way to the end.
And if the string is empty we just return empty. That wasn’t so hard was it? Next up: split!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | our List multi method split($delimiter, $limit = *) { my Int $prev = 0; my $l = $limit ~~ Whatever ?? Inf !! $limit; my $s = ~self; if $delimiter eq '' { return gather { take $s.substr($_, 1) for 0 .. $s.chars - 1; } } return gather { my $pos = 0; while $l > 1 && $pos < $s.chars && defined ($pos = $s.index($delimiter, $prev)) { take $s.substr($prev, $pos - $prev); $prev = [max] 1 + $prev, $pos + (~$delimiter).chars; $l--; } take $s.substr($prev) if $l > 0; } } |
I won’t explain anything again if I already explained it once. So the first new thing we see here is an actual method signature. $delimiter: this means we have a $delimiter value passed in. $limit = *: somewhere Larry Wall wrote that he imagined a language called STAR in which verbs would all be * and they would just DWIM. This is related to that idea. We’ll get to it when we use $limit.
my Int $prev = 0: we are defining $prev to be only an integer and it starts off as 0.
my $l = $limit ~~ Whatever ?? Inf !! $limit: * has a special relationship to Whatever. Whatever is a type of *, so * does Whatever. The idea is that we are matching $limit with whatever, which in this case means only true if the user passed in a value for $limit. Otherwise $limit gets set to Inf, which unsurprisingly means infinity. A little weird. I may clarify this later.
my $s = ~self: We are coercing self into a string here.
return gather: gather/take is a really cool control structure that lets you generate an array without any temporary variables. So you pass gather a block and then any time take is called in the block it pushes the value passed to take onto the generated array. Pretty awesome right?
So the first gather is called if our delimiter is ”, which means get the string as an array. We iterate from 0 to the last character in the string, and give the value of the character (single character string) to take. Fairly simple besides grokking gather/take and wondering where $_ came from till you see the for later on in the line.
The next half of the method basically repeats over the whole string looking for delimiters. It has the following conditions:
we haven’t split more than we originally intended (limit)
and we haven’t gone past the end of the string
and we have a position on the next delimiter in the string
Then we take the string starting at the previous delimiter till the position of the current delimiter. I personally would have defined $prev inside of the second gather as that is the only place that it’s used, but that’s just me
Next we set $prev to the maximum of one more than the last delimiter and the current delimiter + the length of the delimiter. This is a really strange line of code, but so it goes. First off, we are using the reduce operator ([]) to find the max. I would have used just max as we are only comparing two things; not a big deal of course. I also cannot think of a time when the first option would even be greater than the second, only equal to it. I am probably wrong though…
Then we decrement $l, which is our max amount of splits.
And then we end by taking the rest of the string if there are any “splits” left. Again, the if statement there seems superfluous. But I could be wrong.
I tested my theories about extra code and it still seems to work fine. Here is my new and imFrewved method
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | our List multi method split($delimiter, $limit = *) { my $l = $limit ~~ Whatever ?? Inf !! $limit; my $s = ~self; if $delimiter eq '' { return gather { take $s.substr($_, 1) for 0 .. $s.chars - 1; } } return gather { my Int $prev = 0; my $pos = 0; while $l > 1 && $pos < $s.chars && defined ($pos = $s.index($delimiter, $prev)) { take $s.substr($prev, $pos - $prev); $prev = $pos + (~$delimiter).chars; $l--; } take $s.substr($prev); } } |
11 Mar
Another tutorial posted here. This goes over functions, references, regular expressions, and perl’s case statement (given/when).
Enjoy!
11 Mar
Brave by Marillion
is this weeks Album of the Week. Before I get into specifics I need to tell a story about how I got into Marillion…
I found out I loved prog music because of Transatlantic. Marillion’s Pete Trewavas is one of the members of Transatlantic. I checked out all of the other band member’s groups, but I never did check out Marillion (as in order a CD.) One day I was in the thrift store and I happened upon a Marillion album (Season’s End
.) It was surprisingly good and I bought up a few more albums (Misplaced Childhood
, Fugazi
, and some other one I can’t find.) Anyway, I just cannot believe that I found music that excellent at a thrift store.
Back to Brave. Brave is one of the earlier Marillion albums, yet it still falls into the “Hogarth” era Marillion. I would compare Marillion with Radiohead, except I don’t really like Radiohead enough to know them that well. Marillion often has fairly dark music, and Brave is no exception. I have never actually noticed the lyrics on Brave (except for The Great Escape,) but Brave is a concept album. I recommend reading the lyrics instead of listening to me about that though.
I would also describe this album as very heartfelt; that is, I would say that feeling and meaning tend to bleed through. I would compare this to how I feel about The Arcade Fire.
Brave is one of those albums that you really should listen to in its entirety. It has a great intro and an excellent finale. Brave is a good album to listen to when it’s pouring rain out and you just feel like brooding.
Favorites: Bridge, Living with the Big Lie, Hard as Love, Brave, The Great Escape.
Colors: Black, Navy.
9 Mar
Hello everyone!
Hopefully you know that today (March 9-10, starting and ending at sundown) is the holiday of Purim!
I just want to mention that the best way to celebrate Purim (we did this at school) is to read the entirety of the book of Esther out loud, cheering for Mordecai (or Esther, but not both,) and booing at Haman, and each time you cheer or boo, you take a drink. At school we used non alcoholic sangria, which I think was worse than what wine or beer would have been because of all the sugar and carbonation.
Anyway, celebrate!
9 Mar
I just posted a workflow for Git on the Rakudo Wiki. Hopefully it works well and helps people use Git and work on Rakudo. Enjoy!
7 Mar
I like to make playlists. But I also reorganize my music something like once or twice a year. Because of that my playlists get broken as they are really just lists of filenames. This past summer I wrote some code in ruby that would find files with the same basename but ignore the directory structure, and reconstruct playlists from that. It worked perfectly except every now and then I would get a live version or two. This works because I have an sqlite database of all of my music thanks to amaroK.
Well, I decided that I would update the script so that I wouldn’t have those issues with live versions. I decided that I would have an intermediate filetype, which I would basically keep around forever. Announcing the FRU media playlist filetype! Actually not that exciting. Anyway, here are a couple scripts:
m3u2fru.pl6:
fru2m3u.pl6:
But the more important part, is the Ghetto module. Currently rakudo does not have any way to get the output of a command, but it can read from files, so we can fake it:
Obviously this is slow, bad in that it could possibly overwrite files, etc. It’s ghetto. But the idea is that later when we actually can do something like this without a ghetto solution it won’t be hard to fix your code.
I also thought it was fun to do a pipe-based solution. The way I had it set up before was something like this:
1 | ./plup.rb old.m3u new.m3u |
That’s alright, but I would usually look at the output to make sure it was right. Now I do this:
1 | cat old.m3u | ./m3u2fru.pl6 | ./fru2m3u.pl6 > new.m3u |
Sure it’s longer, but I can easily see the output at any point in the process. Furthermore, since I am using zsh (maybe bash can do this too, not sure) I can do this:
1 | cat old.m3u | ./m3u2fru.pl6 >new.fru | ./fru2m3u.pl6 > new.m3u |
So I can keep the intermediate results for next time!
6 Mar
Did you do a reduce and get confused about how it got the final answer? Do you just want to see the computer write out it’s work? Check it:
1 2 3 4 5 6 7 8 9 10 11 12 | (1,2,3).reduce({ $^a / $^b }) RESULT«0.166666666666667» (1,2,3).reduce({"($^a / $^b)"}) RESULT«"((1 / 2) / 3)"» (1,2,3).reduce({ $^b / $^a }) RESULT«1.5» (1,2,3).reduce({"($^b / $^a)"}) RESULT«"((3 / 2) / 1)"» |
How cool is that?