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'