「ふつうの Haskell プログラミング」一人読書会(2日目)
「ふつうのHaskellプログラミング」という本を読んでいます。
ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門
さて、今日は2章の残りと演習問題をやってみました。
まずは head です。ここで実装するのは、標準入力をうけて、先頭10行だけ表示する、というサブセット版だそうです。
例によって、普通の Perl で書くとこんな感じでしょうか
#!/usr/bin/perl use strict; use warnings; my $count = 0; while( <> ) { last if ( $count++ >= 10 ); print $_; }
で、Haskell 風に書くとこうなりました
#!/usr/bin/perl use strict; use warnings; sub first_n_lines { my ($n_lines, @lines) = @_; return join "", @lines[0 .. $n_lines-1]; } print first_n_lines(10, <>);
Haskell では take をつかうのですが、Perl には無いので、ふつうに配列スライスで取り出しています。相変わらず、変数の代入が無い美しいコードですね (棒
続いて、tail です。こちらも末尾10行だけ表示するサブセット版です。で、ふつうに書こうと思ったら、結構難しいんだよな、コレ。普通に書いたやつもゴルフ用みたいなコードになってしまいました。。。
#!/usr/bin/perl use strict; use warnings; my @lines = <>; print @lines[ $#lines + 1 - 10 .. $#lines];
で、Haskell 風がこっち
#!/usr/bin/perl use strict; use warnings; print last_n_lines(10, <>); sub last_n_lines { my ($n_lines, @lines) = @_; return join '', take_last($n_lines, @lines); } sub take_last { my ($n_lines, @lines) = @_; return reverse ((reverse @lines)[0 .. $n_lines-1]); }
なんかどっちも変ですね。。。
最後に、演習問題です。最初は標準入力から与えられたバイト数を数えます。
ふつうの Perl で書くとこんな感じでしょうか。(use bytes しといたほうがいいけど、まあいいや)
#!/usr/bin/perl use strict; use warnings; my $bytes = 0; while( <> ) { $bytes += length $_; } print "$bytes\n";
Haskell ふうに書くとこうなりました。
print length join('', <>), "\n";
最後の改行は、文字列連結(.)を使っちゃダメだぞ!(length に連結された文字列が渡っちゃってうまく行かない。)*1
もう一問は、入力の単語数を数えるコマンドだそうです。「単語」の定義は Haskell の words 関数とするそうです。
Perl で書くときはめんどいので、勝手に split /\s+/ にしちゃいました。
普通にかくとこんな感じです。
my $num_words = 0; while ( <> ) { my @words = split /\s+/, $_; $num_words += scalar(@words); } print "$num_words\n";
Haskell ふうに書くとこうなりました。
print scalar( split(/\s+/, join('', <>) ) ), "\n";