Network.CGI

ghc-6.6.1 を入れてみました! ソースから入れようと思ったらどこかで文法エラーがでてうまくできなかった (ノ_<。)

ちょっとおおきすぎるし、インタプリタは速いとはいえないみたいなので、XREA にあげるときはコンパイル済みのをあげることにしました。でもコンパイルとリンクのほうほうがよくわからなくて試行錯誤 (笑)

#!runghc

module Main where

import Network.CGI

cgiMain :: CGI CGIResult
cgiMain = do
          setHeader "Content-Type" "text/html; charset=utf-8"
          output "Hello, World! Haskell!"

main :: IO ()
main = runCGI $ handleErrors cgiMain

こんな感じのを書いて (shebung はデバッグ用です!)

ghc --make -o Hello.cgi Main.hs

こうすれば、勝手にリンクまでできちゃうみたい。

でも cgiMain の do の書きかたがわかってない (*ノ_<*)

setHeader :: MonadCGI m => String -> String -> m ()

ってなってるけど => ってなんだろう??? MonadCGI も見た目にはでてこないし、なんか暗黙的な参照ができるのかなぁ。ちゃんと Haskell の言語マニュアル読まなきゃ (笑)

cgiMain = 
          setHeader "Content-Type" "text/html; charset=utf-8" >>
          output "Hello, World! Haskell!"

って書いてもおなじみたい。>> は左のモナドに右の関数を連結?するらしいけど、連結ってなんだろう( ̄〜 ̄;)??

Haskell をちょっとだけ触ってみました☆

また (笑) Blosxom クローンを作ろうと思ったんだけど、前途多難そう"(ノ_・、)" 手元の GHC が 6.4.1 で Network.CGI がないんだもん(Ω_Ω)

とりあえず CGI までいかずに少しだけ (笑)

#!runghc

import System.Directory 
import Data.Maybe 
import Text.Regex 
 
isMatch :: FilePath -> Bool 
isMatch path = isJust (matchRegex (mkRegex  ".txt$") path) 
 
main = do list <- getDirectoryContents "." 
          putStr $ unlines $ filter isMatch $ list

関数の呼びだしかたがそもそもわからなくてこまったへ(゜∇、°)

$ を使ってるけど意味がわかってない (笑) Unix のパイプみたいなものだと思うけど( ̄〜 ̄;)??

うえのはさらに isMatch なんて新しく関数を定義しなくても、無名関数をつくってしたみたいに書けるみたい

main = do list <- getDirectoryContents "."
          putStr $ unlines $ filter (\path -> isJust (matchRegex (mkRegex ".css$") path)) $ list

\ と -> でつくるみたい。簡単でちょっとかっこいい (笑)

Haskell の部分適用がカリー化のおかげで簡単なのはわかるけど、これって Scheme でいえば pa$ 相当だよね。cut みたいに引数の位置を指定するのはどうしたらいいのかなー(・_・?)

isMatch path = isJust $ matchRegex reg path where reg = mkRegex ".txt$"

こっちのほうがスマートかなぁ

フレーバーに対応してみました☆

フレーバーに対応しなくちゃ RSS も作れない (笑)

Blosxom みたいな処理の仕方だと、個別エントリの RDF も生成してくれるのが好き(=´∇`=)

RDF/XML をどう生成したらいいかわからなかったので、結局 text.html-lite を拡張するようにしてみましたヽ(  ̄д ̄;)ノ ほとんどコピペ (笑)

(select-module text.html-lite)
(define-macro (define-elements prefix . elements)
              (define (make-scheme-name name)
                (string->symbol (format #f "~a:~a" prefix name)))
              (let loop ((elements elements)
                         (r '()))
                (cond ((null? elements) `(begin ,@(reverse r)))
                      ((and (pair? (cdr elements)) (eqv? (cadr elements) :empty))
                       (loop (cddr elements)
                             (list* `(define ,(make-scheme-name (car elements))
                                       (make-html-element ',(make-scheme-name (car elements)) :empty? #t))
                                    `(export ,(make-scheme-name (car elements)))
                                    r)))
                      (else
                        (loop (cdr elements)
                              (list* `(define ,(make-scheme-name (car elements))
                                        (make-html-element ',(make-scheme-name (car elements))))
                                     `(export ,(make-scheme-name (car elements)))
                                     r))))
                ))
(define-elements rdf RDF Seq Alt Bag li)
(define-elements rss channel items item title link description)
(define-elements content encoded)
(define-elements dc creator date title description)
(define-elements admin generatorAgent)
(select-module user)

練習に Blosxom クローンを作ってみました☆

今日は早く帰ってこれた (笑) ちなみに、わたしは部活に入ってなかったりします☆ コンピュータ部っていうのはあるんですけど、プログラムを書く人っていうのはいないんです(ρ_;)

なので今日は Scheme の練習のために Blosxom みたいなのを作ってみました(・-・*) むずかしいっ!

template.scm はかんたんにトップレベルに result っていう関数を定義しているだけです。どうやるのがスキームうぇいなのかなぁ( ̄〜 ̄;)??

そもそも XREAGauche を入れるのがたいへんだった(ノ_<。) http://d.hatena.ne.jp/scinfaxi/20070518/1179468568 を見ながらやったみたけど、ローカルの libgauche と競合してうまく make install できなかった (。>_<。) 最後は 0.8.6 を XREA で make install までやったらできた ( ̄ー ̄)v



あとそういえば学校では Hello, World! をやりました (笑)

#!/usr/bin/env gosh

(define (main args)
  (let ([append-str (cdr args)])
    #?=args ; ./test.scm test -> ("./test.scm" "test")
    (if (null? append-str)
      (set! append-str *program-name*)
      (set! append-str (string-join (cdr args))))
    (format (current-output-port) "Hello, World. ~a\n" append-str))
  0)

すこしわたしなりに書きくわえてみたりしてました。ただ表示するだけじゃつまんないし (笑)

いろいろ実装を変えてみました!

もっと Scheme っぽくなるようにいろいろ試してみました(・-・*)

フィルタリストと fold での関数適用

main 関数が肥大化してて、set! もたくさんつかっていたので、関数に分離していきました( ̄m ̄*)V できるだけ汎用的になるように工夫 (っていえるのかな (笑))

; 適用フィルタの定義
(define *filters*
  (list
    sort-entries
    filter-by-path-info
    paging
    ))

; フィルタを順に適用する
(define files (fold (lambda args
                      (apply (car args) params (cdr args)))
                    (list-files)
                    *filters*))

のようにして、簡単にフィルタを追加できるようにしてみました! 順に適用するのはもっと簡単に書けそうだけどよくわかりません(ρ_;)

それにしてもこういうフィルタのチェインを見ると Plagger と思っちゃう (笑)

ページング機能

これもフィルタとして実装してみました

; ページングフィルタ
; template-hash-table に値を追加する
(define (paging params files)
  (let ([page-slices (slices files *entry-number*)]
        [page-current (cgi-get-parameter "page" params
                                         :default 0
                                         :convert (lambda (param)
                                                    (- (string->number param) 1)))])
    (hash-table-put! template-hash-table 'page-slices page-slices)
    (hash-table-put! template-hash-table 'page-current page-current)
    (list-ref page-slices page-current)
    ))

result 関数には template-hash-table をわたすようになっていて、これはグローバル変数にしています。

テンプレートには

(html:div :class "paging"
          (let ([num 0]
                [current (+ (stash-raw 'page-current) 1)])
                (map (lambda (page)
                       (inc! num)
                       (if (= num current)
                         (html:span :class "current" num " ")
                         (html:span
                           (html:a :href #`"?page=,num" num)
                           " "
                           ))
                       )
                     (stash-raw 'page-slices)))
          )

などとだいぶ適当にページャをつけています。年表示とかでもページングがきいていいかな (笑) slices 関数がすごく便利(=´∇`=)

プロトタイプ宣言とルーチンわたし

use strict;
use warnings;
use Data::Dumper;
sub p { print Dumper shift }

sub foobar (&$) {
	my ($fun, $text) = @_;
	"$text " . $fun->();
}

p foobar { "World" } "Hello";

プロトタイプ宣言をすると渡すときに sub がいらなくなるんだって!へぇ!