HGL

今が旬の赤紫蘇を使って、紫蘇ジュースを造ってみた。作り方は、Googleおばさんに聞いて ください。いろいろあって、微妙に違っていたりして、面白いです。

熱湯に、紫蘇の葉を入れて暫くすると、葉の色素が湯に溶け出して、葉が緑色になる。抽出液 に、酢を加えると、赤黒かった液がruby色になるのが、理科の実験みたいで面白かったです。 砂糖の量を控えておくと、焼酎割りにも最適! rubistは、ルビー色に輝く飲み物を補給 しながら、Hackにいそしんでください。

Haskellの配列

rubyのサンプルをHaskellに置き換えようとすると、どうしてもHaskell上で使える配列が欲しくなる。 どうやって使うんだろうと思って、調べてみた。

import Array
lang = listArray(1,4) ["haskell", "Scheme", "Ruby", "C#"]
best = lang ! 1
best' = lang // [(4, "Clojure")]

*Main> :load "c:/sakae/HS/ar.hs"
[1 of 1] Compiling Main             ( C:\sakae\HS\ar.hs, interpreted )
Ok, modules loaded: Main.
*Main> lang
array (1,4) [(1,"haskell"),(2,"Scheme"),(3,"Ruby"),(4,"C#")]
*Main> best
"haskell"
*Main> best'
array (1,4) [(1,"haskell"),(2,"Scheme"),(3,"Ruby"),(4,"Clojure")]

2行目で、配列を定義し、3行目で、アクセス、最後の行で書き換え。更新は出来ないのが 微妙(何、この仕様はROMですか) 更に痛いのは、定義したサイズを埋めないと、エラーに なってしまう事。

これじゃ、普通にイメージしてる配列とは大違いだ。Data.Array.IOとかを使うと、普通の配列と 同様な操作が出来るらしいけど、IOがネックかな。Hashを使った方が自由度が高そう。

実用サンプルはどうしてるの?

向井さんの 「入門Haskell」をぱらぱらと、めくってみた。そしたら、 samegameの例が出てきて。。。 List構造になってましたね。やっぱり基本ですよね。切り貼り も簡単だし、豊富に関数が揃ってますから。

でも、Listは、順番にアクセスする必要があるのは、テープと一緒。ランダムアクセスが出来ない のが痛い。嗚呼、テープの切り貼りって昔、よくやりましたよ。1インチ幅の紙テープを使って いた頃、たまにパンチミスをすると、もったいないので、その部分を切り取って、新しいテープで 置き換えてしまう。これが、本当のPatchです。

更に、ソースプログラムのdiffは、、、 薄いLP用紙に印刷して、それを新旧2枚重ねて、 Sun に透かしてみる。違いが一発で検出できます。なんて言う昔話をしてるんだよう。

HGL

この向井本の例を見ていくと、samegameをGraphicsにしましょう、となってHGLが紹介されて いる。FreeBSDにHGLを入れてみた。(libgmpが新しいのを要求され、古いのを消したらghcが 動かなくなった。慌てて、新しいlibraryからリンクを貼ってごまかしてしまったのは、秘密だ)

ぐぐったら、HGLのサンプルを何方かが紹介されてたので、忘れないように貼っておく。

module Main where

import Graphics.HGL

-- スクリーン情報
width::Int
width  = 320
height::Int
height = 240
widthF::Float
widthF  = 320.0
heightF::Float
heightF = 240.0

-- ボールオブジェクト
data BallObj = BallObj {
    x, y   :: Float,
    dx, dy :: Float
}

-- ボールから座標を取得
toPos::BallObj -> Point
toPos ball = (round $ x ball, round $ y ball)

-- 色定義
color = RGB 255 255 0

-- 描画関数を返す
drawball:: Point -> Graphic
drawball (x,y) =
    do withRGB color $ ellipse (x-10, y-10) (x+10, y+10)

-- 描画
draw::[BallObj] -> Graphic
draw balls =
    do mapM_ drawball $ map toPos balls

-- 移動
moveBall:: BallObj -> BallObj
moveBall ball =
    BallObj {
        x  = (x ball) + (dx ball),
        y  = (y ball) + (dy ball),
        dx = (dx ball),
        dy = (dy ball) }

-- 状態の更新
updateState::[BallObj] -> [BallObj]
updateState balls = (map boundBall (map moveBall balls))

-- 初速
speed0 = 0.5
-- ボール達
balls= [
    BallObj{dx=  speed0*4, dy=  speed0,   x=0,      y=0},
    BallObj{dx= -speed0,   dy=  speed0*4, x=widthF, y=0},
    BallObj{dx= -speed0*2, dy= -speed0*3, x=widthF, y=heightF},
    BallObj{dx=  speed0*3, dy= -speed0*2, x=0,      y=heightF} ]

-- 跳ね返り
boundBall::BallObj -> BallObj
boundBall ball =
    let
        px = x ball
        py = y ball
        vx = if px < -3 || px > widthF+3
                then -(dx ball) -- 反転
                else dx ball
        vy = if py < -3 || py > heightF+3
                then -(dy ball) -- 反転
                else dy ball
    in
        BallObj {
            x  = px,
            y  = py,
            dx = vx,
            dy = vy }

-- ゲームループ
-- ウィドウ -> ボールオブジェクト
loopGame::Window -> [BallObj] -> IO()
loopGame w balls =
    do e <- maybeGetWindowEvent w
       -- イベント処理
       case e of
        Just(Char {char=c}) ->
            -- ESCキー
            if c == '\ESC'
                then closeWindow w
                else loopGame w balls
        Nothing -> do
            -- 描画処理
            setGraphic w $ do
                draw balls
            getWindowTick w
            loopGame w (updateState balls)
        _ -> loopGame w balls

-- エントリポイント
main::IO()
main = runGraphics $ do
    w <- openWindowEx "test" Nothing (width, height) DoubleBuffered (Just 3)
    -- ループ開始
    loopGame w balls

Windows では?

HGLはWindows上でも動くとの事なので、試してみた。

c:\>cabal.exe install HGL
Warning: The package list for 'hackage.haskell.org' is 16 days old.
Run 'cabal update' to get the latest list of available packages.
Resolving dependencies...
Downloading HGL-3.2.0.0...
Configuring HGL-3.2.0.0...
Preprocessing library HGL-3.2.0.0...
Building HGL-3.2.0.0...

Graphics\HGL\Key.hs:57:7:
    Could not find module `Graphics.Win32':
      it is a member of the hidden package `Win32-2.2.0.0'
      Use -v to see a list of the files searched for.
cabal.exe: Error: some packages failed to install:
HGL-3.2.0.0 failed during the building phase. The exception was:
exit: ExitFailure 1

見事に失敗してます。ググってみたら、やはり世界中に悲しい思いをしてる人が いました。解決方法は提示されていません。

そこで、チャレンジしてみました。ghciなら、よく見えると思ったのでした。

c:\sakae\HGL-3.2.0.0>ghci
GHCi, version 6.10.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer ... linking ... done.
Loading package base ... linking ... done.
Prelude> :load Setup.hs
Ok, modules loaded: Main.
Prelude Main> :main build
Loading package syb ... linking ... done.
Loading package array-0.2.0.0 ... linking ... done.
Loading package containers-0.2.0.1 ... linking ... done.
Loading package bytestring-0.9.1.4 ... linking ... done.
Loading package old-locale-1.0.0.1 ... linking ... done.
Loading package old-time-1.0.0.2 ... linking ... done.
Loading package filepath-1.1.0.2 ... linking ... done.
Loading package Win32-2.2.0.0 ... linking ... done.
Loading package directory-1.0.0.3 ... linking ... done.
Loading package process-1.0.1.1 ... linking ... done.
Loading package pretty-1.0.1.0 ... linking ... done.
Loading package Cabal-1.6.0.3 ... linking ... done.
Preprocessing library HGL-3.2.0.0...
Building HGL-3.2.0.0...

Graphics\HGL\Key.hs:57:7:
    Could not find module `Graphics.Win32':
      it is a member of the hidden package `Win32-2.2.0.0'
      Use -v to see a list of the files searched for.
*** Exception: ExitFailure 1

該当部分のソースを見ると、ただ、import してるだけです。そのモジュールを ghci上から import すると、何の問題もなく import できます。そこで、ソースの 該当行を消してしまいました。

これを、丹念に繰り返した所、進展はありましたが、下記の所でちから尽きてしまいました。 どなたか、チャレンジしませんか?

c:\sakae>cd HGL-3.2.0.0\
c:\sakae\HGL-3.2.0.0>runghc Setup.hs build
Preprocessing library HGL-3.2.0.0...
Building HGL-3.2.0.0...
[ 3 of 26] Compiling Graphics.HGL.Internals.Types ( Graphics\HGL\Internals\Types.hs, dist\build\Graphics\HGL\Internals\Types.o )

Graphics\HGL\Internals\Types.hs:50:26: Not in scope: `timeGetTime'