11
4

Haskellを書くときに気をつけていること

Posted at

まずはじめに,私は情報工学出身ですが仕事では概念検討や通信機・OBCなどの設計・研究開発を生業にしています.
Haskellは大学時代から使っていますが,世のHaskeller達のような高度な術式は唱えませんし,高速化などにも実用上困らなければ興味はありません.
VBAを使うExcelユーザのような感覚で業務用ツールに使っている程度,VBAと違うのは社内に自分以外Haskellユーザがいないという点くらいです.

そんな私が,業務用ツールを使うときに気をつけていることをいくつかご紹介します

  1. 置く場所は固定する
  2. 型付けしまくる.数年後に使う時も戸惑わない
  3. 他人が使う可能性のあるものはwebアプリにする
  4. パーサはTrifectaが最強説

置く場所は固定する

プロジェクト毎にフォルダを用意し,資料やOfficeファイルの管理をしています.
当初はスクリプトもプロジェクト毎にフォルダ分けして使う様にしていたのですが,置かれるが全て異なるため,共に置かれているデータファイルや資料との関連が強いスクリプトは見つけやすいものの,やや関連の弱いスクリプトは迷子になりやすく探す時間が惜しいです.

現在は,下のようにスクリプトは全て同じ場所に格納しているのでそういったストレスも,ファイルが見つからず書き直す悲劇も解決しました.
よく使うもので汎用性の高いもの,外部ライブラリへの依存がないものはフォルダ直下に直接置き,そうでないものやプロジェクト固有のものはサブフォルダへ整理しています.

% ls Documents/haskell
Meanda.hs		TCP					Allan.hs
GSE				Antenna.hs			PatchPattern.hs

 ### 型付けしまくる
人間誰しも,生きていれば必ず数年前に作ったスクリプトを使いたくなるときがあります.
そんなとき,変数名が一文字だったり,型がFloatやIntegerとしかかかれていない場合,スクリプトを使う前にもう一度コードを読み直したりする必要が発生することも.
そうならないために,徹底的に型を付けます.

下に,アンテナ利得の管理によく使っているスクリプトを掲載します
(周波数部分はダミー)
一度webで別言語のプログラムを見た時,引数に取る周波数の単位がHzなのかMHzなのか,コードを追いかけないと分からず,またライブラリから提供されているものに関してはライブラリの中身まで見る必要があったり,大変煩わしかったのを覚えています.
以後,私は自分で用意するツールは単位も含めて型で管理するようにしています.
周波数はほぼ全てのスクリプトで使うので,周波数操作関連だけはモジュール化しても良いですね.

module Antenna where

import Numeric (showFFloat)

type     Diameter = Float               -- 直径
type   Efficiency = Float               -- 開口率
type BeamWidth3dB = Float               -- 3dBビーム幅
type    Frequency = (Float, FreqUnit)   -- 周波数

data Antenna = Antenna Diameter Efficiency Frequency
data FreqUnit = GHz | MHz | KHz | Hz deriving (Eq,Show)

instance Show Antenna where
    show ant@(Antenna d e fq) = "\n\n---- アンテナ情報 ----\n" ++ 
        "直径: " ++ showFFloat (Just 3) d " [m]\n" ++
        "開口率: " ++ showFFloat (Just 3) e "\n" ++
        "波長: " ++ showFFloat (Just 4) (getLambda fq) "[m]\n" ++
        "周波数: " ++ showFFloat (Just 7) (fst fq) (show (snd fq) ++ "\n") ++
        "3dBビーム幅: " ++ showFFloat (Just 3) (getBW3dB ant) " [deg]\n" ++
        "アンテナ利得: " ++ showFFloat (Just 4) (getGain ant) "[dBi]\n" ++
        "------------------------\n"

c = 299792458 -- m/s

ant3_2 = Antenna 3.2 0.5
ant12 = Antenna 12 0.5
ant32 = Antenna 32 0.5

satUL, satDL :: Frequency
satUL = (435.110, MHz)
satDL = (435.210, MHz)

getBW3dB (Antenna d _ fq) = 70 * getLambda fq / d

setEfficiency e' (Antenna d e f) = Antenna d e' f

getLambda (fq, GHz) = c / (fq * 10^9)
getLambda (fq, MHz) = c / (fq * 10^6)
getLambda (fq, KHz) = c / (fq * 10^3)
getLambda (fq,  Hz) = c /  fq

getGain (Antenna d e  fq) = (*10) . logBase 10 $ e * pi*(pi*d^2) / (getLambda fq)^2

このようにしておくと,記憶を全て失った数年後にまた使いたくなったときも

ghci>:b

ghci>:t getGain

を叩くだけで全て解決です.超ストレスフリーです.

他者も使うときはwebapi

冒頭に書いたとおり,私の職場ではHaskellユーザは一人も居ません.
pythonが圧倒的です.
そのせいで最近,私のpython力が上がりました.でも他人のコードは読めません
私以外,複数人でのソフトウェア開発を誰も経験したことがないので,gitも使えない,引き数名/変数名は適当,コメント・注釈なしの状態でよく回ってきます
しんどいですね

基本的に,自分一人が使い自分一人でメンテすることを想定して作られているのでこうなるわけです.そして誰も使い方が分からないから結局使う人=制作者ただ一人になります.

他人はともかく,自分の用意するツールだけはこのような非効率を生んではいけません.
特に私は人よりも,緊急入院や失神で不在にする可能性が高いわけですから,メンテはともかく万人が使える物にしておく必要があります.
なので,Servantを使ってwebapi化しています.(作例はちょっとお見せできません...)

利点はこの他に,GUIも付けておくとU/Iはhtmlで記述できる点にもあります.
htmlを読めない人間はいませんから,私でなくとも少なくとも表示系は誰でも簡単に操作できます.
あとはGUI操作でも,必要であればpythonなどからapiを叩いて貰えば解決するわけです.

パーサはTrifecta

他の言語にも優れたパーサがあるのだと思いますが,日本語が使えない(え,使えないですよね?)ことを除けば個人的にはTrifectaは非常に書きやすく変更も容易で重宝しています.
私の職場ではjsonを知っている人すら少なくデータはexcelやtextで貰うことが多いのですが,例えばTLE(two line elements:軌道要素の格納されたテキストデータ)がわかりやすいでしょうか.これから衛星IDや各軌道要素を取り出すのにもTrifectaを使っていますし,xmlや,他人のツールが吐いたデータのフォーマッタにも利用しています.

おわり

こういったことに気をつけながら,個人業務で使うもの以外にも,
広報用のtwitter自動投稿ツールや地上テレメトリ監視ソフトウェアも作っています.

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4