プログラムの初期の段階で値が決まった変数をプログラムの底の方で参照したい。例えばコマンドラインパラメタや設定ファイルの中身を参照したい。一番手軽なのはグローバル変数だが、クラスメンバー変数でも良い。Pythonではグローバル変数を、Scalaではクラスメンバー変数にしたが、Haskellではどうしたもんか。Haskellでこういった事をどう解決するかは知らないし、ググってもロクな情報が得られなかったので、一番原始的に関数の引数にすることにした。
shuffle_H.hs では、
data Config = Config { option :: OptionParam, priority :: [String], weight :: [(String, Float)] }
という型を定義。それをmain関数で完成させ、各関数にパラメタで渡す。
例えば
listupFiles :: Config -> (Int, Float, String) -> IO [(Int, Float, String)]
これ、このやり方、C言語のFILE *と一緒。Windows APIやMacintosh Toolboxなんかと同じ方法。言語がクラス化されてないからなんらかのハンドルを持ち回すという古典的テクニック。私はこんなやり方しか思い付きませんでした。
どうせなのでScalaやPythonでも似たデータ構造を使う。
case class Config(option: OptionParam, priority: List[String], weight: Map[String, Float]) class Shuffle(cfg: Config) {
Scalaではクラスのパラメタにすることで、クラスメソッド全部から参照できるようになる。端的に手抜きなわけだが。
class Config: def __init__(self): self.priority = [] self.weight = {} self.getWeight() self.option = OptionParam() cfg = Config()
Pythonでは単にグローバル変数。このインスタンスのメンバーはgetWeight()関数などで再代入されるので、やはり縛りからは逸脱してる。変な縛りに拘って不自然なコードを書くのも本末転倒なのでもうこれでいい。
epub2to3_H.hsを書いてる時、fixZip関数で現在日時が必要だと気付いた。ライブラリを調べるとIOモナドが要求されると判明。IOモナドによる汚染である。fixZip関数は汚染なしに書ける見通しだったので悩んだ末、Config型に入れることにした。他にもコマンドラインパラメタで指定されたCSSファイルの中身など、IOモナドに汚染されているデータを汚染から引き離してまとめて入れることにした。汚れ仕事は全部main関数にて行う。
data Config = Config { option :: OptionParam, nowSec :: Integer, nowUTC :: UTCTime, cssText :: String }
こんなやり方が正しいとは到底思えないが、これくらいしか思い付かなかった。ScalaやPythonではnowSecやnowUTCに相当するメンバ変数はない。
2014.07.17
OSTRACISM CO.
OSTRA / Takeshi Yoneki