2014年11月22日土曜日

[linux] DHCPでIPを割り当てているサーバーのIPアドレスをクライアントから確認する方法

DHCPで各マシンのIPを割り当ていている環境では、頻繁にIPアドレスが変わります。このような環境で、常時起動ではないPCサーバーを立てているとクライアントからのアクセス時に、接続先のサーバーのIPアドレスがわからず困ることがあります(特にサーバーにディスプレイをつないでいない場合)。
サーバーがsamba(CIFS)のサーバー機能を持っていると、samba経由であればNetBIOS名でのアクセスは可能ですが、HTTPやSSHでのアクセスにはIPアドレスが必須です。このようなケースで、リモートから簡単にIPアドレスが得られる方法を調べたのでメモ代わりに残しておきます。

準備:サーバーにsamba(ファイルの共有)を設定しておく

今回紹介する方法はNetBIOSを利用しているためサーバー上でsamba、ファイル共有を有効にしておく必要があります。

方法1:nbtstat(windows), nmblookup(linux)を利用する。

  • クライアントがWindowsの場合:nbtstatコマンドを利用する
  • C:\Windows\system32>nbtstat -a pc-server
           : (snip)
    
    C:\Windows\system32>nbtstat -c
    
    イーサネット:
    ノード IP アドレス: [172.16.0.119] スコープ ID: []
    
                      NetBIOS リモート キャッシュ ネーム テーブル
    
              名前              種類       ホストアドレス    継続時間 [秒]
        ------------------------------------------------------------
         PC-SERVER       <20>  一意          172.16.0.94         597
         PC-SERVER       <00>  一意          172.16.0.94         597
    
    
  • クライアントがLinux、macの場合:nmblookup (or smbutil lookup)を利用する
  • 
    % smbutil pc-server
    Got response from 172.16.0.121
    IP address of ubuntu2: 172.16.0.121
    
    % nmblookup pc-server
    querying pc-server on 172.16.255.255
    172.16.0.94 pc-server
    
    

方法2:smbclient, findsmbコマンドを利用する

  • smbclientを利用する。-dはデバッグレベル6を意味する。デフォルトは1だが、1だとサーバーのIPアドレスは表示されない…。
  • 
    % smbclient //pc-server/public -d=6 
          :  (snip)
    Connecting to 172.16.0.94 at port 445
          :  (snip)
          :
    
    

  • findsmbを利用する。
  • 
    % findsmb
    
                                    *=DMB
                                    +=LMB
    IP ADDR         NETBIOS NAME     WORKGROUP/OS/VERSION 
    ---------------------------------------------------------------------
    Can't load /opt/local/etc/samba3/smb.conf - run testparm to debug it
    172.16.0.94     PC-SERVER        [WORKGROUP] [Unix] [Samba 4.1.6-Ubuntu]
    
    

  •  参考:

2014年11月21日金曜日

[mac] Yosemiteへのアップグレード関連作業まとめ

しばらく様子を見ていたのですが、大きな問題はなさそうなのでMac Book AirをYosemiteへアップグレードしました。以下、環境設定、遭遇した問題とその対応など、作業ログ的なものを残しておきます。

準備

  • アップグレード失敗に備えてMarvericks環境でTime Machineをセットアップし、バックアップをとった。手順はこちらを参考に。

アップグレード後の作業

  • Marvericks環境で利用していた設定・ソフトのセットアップ
    • キーボートショートカットの設定
      • [設定] - [キーボード] - [ショートカット]に以下の設定を復活
        • この設定がないとGoogle Chrome上でMeta-Wキーが「タブを閉じる」動作になってしまい、Krabinerのemacs keybindの威力が半減してしまいます。その他、以下の設定を追加しています。
          • CTRL-U: 「ソースを表示」
          • ALT-N: 「次を検索」
          • ALT-P: 「前を検索」
          • ALT-W: 「コピー」
    • XQartz
      • Marvericksアップグレード後、XQuarzを最新版にアップデート。一晩待ってもファイル抽出中のダイアログが出たまま終了しない、という症状が出た(PC再起動で強制終了)が、その後特に問題は出ていない模様。
    • Karabiner
      • アップグレード後、自動起動されない状態になったが、一度手動で起動すると、以前の設定が引き継がれ有効になった。
        • emacs keybind設定
        • Use KANA as KANA/EISUU (toggle)で「かな」キーでことえりのon/offがトグルするようになる
  • haskell環境の問題(cabal installでコンパイルエラーが発生)の復旧
    • Mountain LionからMarvericksへのアップグレードでも発生した、cabal installでエラーが発生する問題が今回も再現。前回と同じ手順で復旧。
    • 
      % xcode-select --install
      
      
  • emacsでCTRL-Nが効かなくなった問題に対応
    • ここの情報を参考に対応(助かりました・・・)。[システム環境設定] -> [キーボード] -> 入[力ソース]で[日本語]を選択し、[Windows風キー操作] のチェックを外すとOK!
  • wiresharkが起動できなくなった問題に対応
    • ここの情報を参考に、/opt/X11へのシンボリックリンンクを/usr/X11に作ったところ、正常に起動するようになりました。
    • 
      % cd /usr; sudo ln -s /opt/X11 .
      
      

参考:

[mac] LinuxマシンをTime Machineのバックアップ先ディスクとして利用する方法

ネット上の情報を参考に、Mac Book Airのバックアップ先としてLinux PC(Ubuntu 14.04 LTS)を利用するよう設定することができました。sambaサーバーをバックアップ先に指定して、Time Machineを利用できる状態になります。

Linux PCの設定

  • sambaをインストールし、メインユーザーのホームディレクトリを公開設定する

MacBookAirの設定

  • 以下のサイトの手順に従って設定。
  • Finderのメニューで[移動] - [サーバーに接続]で、Linux PCに接続しておく必要がある
    • 公開設定したホームディレクトリを指定。例: //server-name/public-dir。

バックアップの開始時、終了間際に固まる問題に遭遇しましたが、以下のコマンドを実行して、バックアップ先ファイルのロックを外してあげる?と先に進められるようです。


sudo mdutil -i off /Volumes/TimeMachine/Backups.backupdb


Marvericks環境では、この固まる問題が発生していましたが、Mac Book AirをYosemiteにアップグレードしたところ問題は発生しなくなりました!

参考:

2014年10月6日月曜日

[windows][emacs] Windows 8.1上で(特定ユーザーログイン時に)任意のアプリの操作をemacsキーバインドにする方法

windows 8.1上のすべての操作をemacsキーバインドにできないか、と思ってネット上の情報を探したところ、keyhacというぴったりのツールが見つかりました。カスタマイズが自由&簡単、かつクリップボード履歴機能つき!

自分としては以下の設定ができれば目的達成です。
  • CapsLockをCtrlキーに
  • IMEのon/offを変換キーで
  • カーソル移動・クリップボード関連操作などをemacsキーバインドに
  • 可能であれば特定ユーザー(自分のアカウント)ログイン時のみ限定したい・・・
こちらのブログで紹介されているpythonスクリプトを、keyhac.exeと同じディレクトリにconfig.pyという名前で保存するだけでemacsキーバインドが実現できました。感謝。

config.pyのカスタマイズ方法:

せっかくなのでkeyhacのconfig.pyによるカスタマイズ方法を簡単に紹介しておきます。
config.pyでは任意のアプリ上のオリジナルのキー操作をpythonスクリプトで記述することができ、それをkeyhac上のキー操作に割り当てることで、キーバインドを実現しています。
たとえば「ペースト」はyank()という関数で以下のように定義されています。
    
            def yank():
                keymap.command_InputKey("C-v")()
                keymap_emacs.is_mark = False
    
    
それをkeymap_emacsでCtrl-yにバインドしています。
    
            keymap_emacs["C-y"]             = reset(yank)
    
    
上記のような感じで、簡単に設定が可能です。以下、自分の環境にあわせて追加した設定を紹介しておきます。
  • IMEのon/offを変換キーに割り当てる
  • 
        keymap.replaceKey( 28, 243 )
    
    
  • config.pyの編集には秀丸を利用(※"\"はエスケープが必要)
  • 
        keymap.editor = u"C:\\Program Files\\Hidemaru\\Hidemaru.exe"
    
    
  • キーバインドを変更しないアプリにexplorerとemacs-X11を追加
  • 
        def is_emacs_target(window):
            if window.getProcessName() in (# skip...
                                           "explorer.exe",       # explorer
                                           "emacs-X11.exe",      # Emacs-X11
    
    
    
  • ついでにforward/backward wordとdelete wordの定義を追加
  • 
        def forward_word():
            keymap.command_InputKey("C-Right")()
        def backward_word():
            keymap.command_InputKey("C-Left")()
        def delete_word():
            keymap.command_InputKey("C-S-Right")()
            kill_region()
            keymap_emacs.is_mark = False
        def delete_backward_word():
            keymap.command_InputKey("C-S-Left")()
            kill_region()
            keymap_emacs.is_mark = False
    
        keymap_emacs["A-b"]             = repeat(mark(backward_word))
        keymap_emacs["A-f"]             = repeat(mark(forward_word))
        keymap_emacs["A-d"]             = reset(delete_word)
        keymap_emacs["C-Back"]          = reset(delete_backward_word)
    
    

keyhacで実現できないキーバインド:

残念ながら、[Ctrl]と[Caps Lock]の入れ替えのみ、keyhacでは実現できませんでした。これは、ドライバのレイヤで、[Caps Lock]のUPイベントを抑制しているのが原因のようです。keymap.replaceKey( "LCtrl", 240 )という設定をしても意図した動作になりません。
仕方がないのでここの情報に従いレジストリをいじって、[Caps Lock]をつぶして[Ctrl]にすることで対応しています。入れ替えではなく上書きなので、本来の[Ctrl]と[Caps Lock]の両方が[Ctrl]の役割を持っている状態です。このため[Caps Lock]に[Ctrl]に割り当てる設定だけは、特定ユーザー限定という設定ができませんでした。

(2014/10/06追記)
C-k, A-d, C-BSなど範囲選択後、切り取りをするスクリプトはタイミング依存の問題(?)があるようで、keyhacの「内部デバッグ」をOFFにしていると、期待通り動作しないようです。手元の環境ではONにしていると動作しています(が、動作がのろくなるのでOFFにしたい・・・)。

(2016/01/11追記)
Caps LockにCtrlキーを割り当てる手順

  • regeditで以下のキーにScancode Mapという名前でバイナリ値を設定
    • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout
  • 格納するバイナリ値のデータは以下の通り
    • 00 00 00 00 00 00 00 00
    • 03 00 00 00 1D 00 3A 00
    • 3A 00 3A 00 00 00 00 00

keyhac.iniを修正しコンソールウィンドウを非表示に:

デフォルトではkeyhac起動時、コンソールウィンドウが表示されます。このウィンドウを非表示にするには、keyhac.exeが存在しているディレクトリに生成されているkeyhac.iniの[console]セクションに記述されているvisible=1をvisible=0に設定すればOKです。ただし、この設定は公式ドキュメントには記載されていないようなので、自己責任でお願いします。

参考:

ちなみにmacではKarabiner(旧KeyRemap4MacBook)をインストールすれば、簡単にemacsキーバインドが実現できます。

2014年9月27日土曜日

[haskell][persistent][sqlite] Haskellでデータベースを扱うには(Query編)

前回のエントリでpersistentパッケージを用い、簡単なDBアクセスの手順(スキーマ定義、挿入、削除、単純なレコード取得)を紹介しました。今回は、Queryに関する情報をまとめておきます。

このエントリで紹介するQuery:
  • IDを用いた単純な値(レコード)の取得:get
  • UNIQUE制約のキーを用いた値(レコード)の取得:getBy
  • 検索・ソート条件を自由に設定できる検索:selectX
  • SQL直書きによる検索:rawQuery

準備:リストを用いてDBへレコードを一括挿入

  • 様々なqueryの動作を確認するために、予め10件程度のデータをデータベースに格納しておきます。以下、コードになります。
  • gender.hs
  • 
    {-# LANGUAGE TemplateHaskell   #-}
    module Gender where
    
    import Database.Persist.TH
    
    data Gender = Male | Female
        deriving (Show, Read, Eq)
    derivePersistField "Gender"
    
    
    • TemplateHaskellが生成したコードは、生成したのと同じmodule内で使用することはできないため、別ファイルで定義。
  • person.hs
  • 
    {-# LANGUAGE EmptyDataDecls    #-}
    {-# LANGUAGE FlexibleContexts  #-}
    {-# LANGUAGE GADTs             #-}
    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE QuasiQuotes       #-}
    {-# LANGUAGE TemplateHaskell   #-}
    {-# LANGUAGE TypeFamilies      #-}
    import Control.Monad.IO.Class  (liftIO)
    import Database.Persist
    import Database.Persist.Sqlite
    import Database.Persist.TH
    import Data.Conduit
    import qualified Data.Conduit.List as CL
    import Gender
    
    share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
    Person
        name String
        age Int
        gender Gender -- Genderカラム(VARCHAR: Male or Female)
        Name name     -- nameカラムにUnique制約を付与
        deriving Show
    |]
    
    person_list = [(Person "Michael" 26 Male),
                   (Person "Mark" 27 Male),
                   (Person "Jhon" 55 Male),
                   (Person "Cyndy" 25 Female),
                   (Person "Amy" 30 Female),
                   (Person "Linda" 19 Female),
                   (Person "Steve" 42 Male),
                   (Person "Dorothy" 37 Female),
                   (Person "Robert" 40 Male),
                   (Person "George" 15 Male)]
    
    main :: IO ()
    main = runSqlite "person.db" $ do
        runMigration migrateAll
        ids <- mapM insert person_list
        liftIO $ print ids
        return ()
    
    
    • このプログラムを実行するとカレントディレクトリに10人分のデータが登録されたperson.dbというデータベースファイルが生成されます。PersonのリストをmapMで一括insertしています。

IDを用いた単純な値(レコード)の取得:get

  • IDに対応する値がMaybeでラップされて返される。
  • 値が存在しない場合はNothing。
  • person.hsのmainに以下のコードを追加すれば、getの動作を確認できます。
  • 
      -- success to refer Michael
      michael <- get ((Key (PersistInt64 1)) :: Key (PersonGeneric SqlBackend))
      liftIO $ print michael
      -- fail to get with id. Nothing is returned
      noone <- get ((Key (PersistInt64 100)) :: Key (PersonGeneric SqlBackend))
      liftIO $ print noone
    
    
    • printでMaybe Personの内容を表示しています。idに1を指定すると"Michael"のデータが返されます。idに100を指定した場合は該当するレコードが存在しないためNothingが返されます。

UNIQUE制約のキーを用いた値(レコード)の取得:getBy

  • getとほぼ同じ。異なるのは以下の2点のみ。
    1. IDの代わりにUNIQUE制約フィールドを表すUnique値を用いる
    2. Valueの代わりにIDとValueが格納されたEntityが返される
  • person.hsのmainを以下のように書き換えると、getByの動作を確認できます。
  • 
    print_entity Nothing = do
      liftIO $ print "failed to obtain value..."
    print_entity (Just (Entity key person)) = do
      liftIO $ print key
      liftIO $ print person
    
    main :: IO ()
    main = runSqlite "person.db" $ do
      runMigration migrateAll
      -- success to refer Cyndy
      cyndy <- getBy $ Name "Cyndy"
      liftIO $ print cyndy
      print_entity cyndy
      -- fail to get with Name. Nothing is returned
      noone <- getBy $ Name "NotFoundName"
      liftIO $ print noone
      print_entity noone
    
    
    • print_entityでEntityの内容を表示しています。"Cyndy"という名前でgetByした場合には"Cyndyl"のデータが返されます。DBに存在しない"NotFoundName"で検索した場合には、Nothingが返され"failed to obtain value..."という文字列が出力されます。

検索・ソート条件を自由に設定できる検索:selectX

    • select関連関数
      • selectSource
        • 引数:FilterのリストとSelectOptのリスト
        • 返値:IDとValueが格納されたEntityリスト(conduitによるストリームデータ)
      • selectList
        • 引数:FilterのリストとSelectOptのリスト(selectSourceと同じ)
        • 返値:IDとValueが格納されたEntityのリスト
      • selectFirst
        • 引数:FilterのリストとSelectOptのリスト(selectSourceと同じ)
        • 返値:先頭のIDとValueを格納したEntity(空の場合はNothing)
      • selectKeys
        • 引数:Filterのリスト
        • 返値:IDと指定カラム値(レコード全体は返されない)
    • 引数の詳細
      • Filter
        • 結果を絞り込む条件をリストで表現
          • equal(==.)
          • not equal(!=.)
          • more than or equal(>=.)
          • more than(>.)
          • less than or equal(<=.)
          • less than(<.)
          • is member(<-.)
          • is not member(/<-.)
        • AND/ORの表現
          • AND:一つのリストの中にならべた条件はAND
          • OR:リストとリストを(||.)で結ぶ
      • SelectOpt
        • ソート条件(Asc/Desc)
        • 取得開始位置(OffsetBy)
        • 取得結果数(LimitTo)
    • selectListのサンプルです。
    • 
        -- 厄年(男性:25 or 52 or 62, 女性:19 or 33, 37)の人を検索し名前順で取得
        found <- selectList
                 ( [PersonGender ==. Male, PersonAge <-. [25, 42, 61]]
                   ||. [PersonGender ==. Female, PersonAge <-. [19, 33, 37]] )
                 [ Asc PersonName ]
        -- 結果として得た Entity のリストを順に表示
        liftIO $ mapM print found
      
      
      • 厄年に該当する人を名前順に並べて取得して表示するコードです。GenderにMail/Femail以外を指定したり、PersonAgeに数値以外の型を指定するとコンパイル時の型チェックでエラーを検出してくれます。

    SQL直書きによる検索:rawQuery

    • SQLを直に指定して検索することも可能です。
    • raqQueryの型:
    • mainの中に以下のコードを追加するとSQLを直に与えて、結果を得ることができます。
    • 
        -- 名前が"y"で終端するPersonを検索
        let sql = "SELECT name FROM Person WHERE name LIKE '%y'"
        rawQuery sql [] $$ CL.mapM_ (liftIO . print)
      
      


    参考にしたサイト

    2014年8月31日日曜日

    [haskell][persistent][sqlite] Haskellでデータベースを利用するには

    HaskellでDBの読み書きをするにはどうすればいいか?
    yesodのpersistentパッケージが利用できます。本家のサイトを参考にpersistentパッケージの特徴と、簡単な処理を行うサンプルをまとめました。

    persistentパッケージの特徴

    • 「型安全、簡潔、宣言的」という原則に従う
    • DB(PostgreSQL, SQLite, MySQL, MongoDB, etc.)に依存しないAPI
    • 安全で生産的なクエリーインターフェース
    • 他のプログラミング言語からのDBアクセスも考慮
    • yesodに含まれているが、独立したライブラリとして利用可能

    主要な型の説明

    • PersistValue
      • persistentの基本構成要素。DBから出し入れする値を表すデータ型。
      • 
        data PersistValue = PersistText Text
                          | PersistByteString ByteString
                          | PersistInt64 Int64
                          | PersistDouble Double
                          | PersistRational Rational
                          | PersistBool Bool
                          | PersistDay Day
                          | PersistTimeOfDay TimeOfDay
                          | PersistUTCTime UTCTime
                          | PersistZonedTime ZT
                          | PersistNull
                          | PersistList [PersistValue]
                          | PersistMap [(Text, PersistValue)]
                          | PersistObjectId ByteString -- ^ intended especially for MongoDB backend
        
        
        
    • PersistField
      • リレーショナルデータベースのカラムに対応。Haskellの任意のデータ型(datatype)とPersistValueを相互にどうマーシャリングする手順を定義する。
    • PersistEntity
      • PersistentEntityのインスタンスはリレーショナルデータベースのテーブルに対応する。
    • PersistentStore
      • 各データストア(PostgreSQL, SQLite, MongoDB, etc.)はPersistentStoreのインスタンスを持つ。PersistentValueからDB固有の値への変換が行われる。
      • runSqliteは引数で渡されたconnection stringを用いて、DBへのコネクションを一つ生成する。一回のrunSqliteの呼び出しは、一つのトランザクションの中で実行される。
    • 対応関係
      • persistentの型と、データベースの対応関係を整理すると以下のようになる。
      • persistentSQL
        PersistValueデータの型(VARCHAR, INTEGER, etc)
        PersistFieldカラム
        PersistEntityテーブル
        PersistStoreデータストア(PostgreSQL, SQLite, MySQL, MongoDB)

    データのINSERT/SELECTサンプル

    以下の処理を行うサンプルを掲載しておきます。個々の処理が何を意味しているのかはコメントを参考にしてください。
    • personテーブルを生成
    • レコードを一つINSERT
    • SELECTで登録したレコードを取得
    • 取得したレコードを表示

    
    {-# LANGUAGE EmptyDataDecls    #-}
    {-# LANGUAGE FlexibleContexts  #-}
    {-# LANGUAGE GADTs             #-}
    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE QuasiQuotes       #-}
    {-# LANGUAGE TemplateHaskell   #-}
    {-# LANGUAGE TypeFamilies      #-}
    import Control.Monad.IO.Class  (liftIO)
    import Database.Persist         -- persistentパッケージ
    import Database.Persist.Sqlite  -- persistent-sqliteパッケージ
    import Database.Persist.TH      -- persistent-templateパッケージ
    
    -- mkPersist
    --   mkPersist :: MkPersistSettings -> [EntityDef SqlType] -> Q [Dec]
    --   データ型、PersistentEntityインスタンスを生成
    -- sqlSettings
    --   mkPersistの挙動を変える設定値
    -- mkMigrate "migrateAll"
    --   マイグレーション処理を定義
    -- QuansiQuotes [xx|..|] でスキーマ定義。
    --   persistentLowaCaseはテーブル名・フィールド名に、"_"区切り小文字を
    --   利用することを指示している。
    share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
    Person             -- personテーブル。プライマリキーとして"id"カラム自動生成。
        name String    -- nameカラム(VARCHAR, NOT NULL制約)
        age Int Maybe  -- ageカラム(INTEGER, MaybeはNULLを許容することを意味する)
        deriving Show
    |]
    
    main :: IO ()
    main = runSqlite ":memory:" $ do -- DBオープン時の引数。メモリDB利用。"test.db"等の
                                     -- ファイル名を渡すとファイルDBがオープンされる。
        -- personテーブル生成
        runMigration migrateAll
    
        -- name: "Michael", age: 26 のレコードを INSERT
        -- id(プライマリキー)が返値として返される。
        michaelId <- insert $ Person "Michael" $ Just 26
        -- id でレコードを SELECT。該当レコードが返される。
        michael <- get michaelId
        -- 返されたレコード(Personインスタンス)を表示。
        liftIO $ print michael
    
    


    Uniqueness

    大文字から始まるデータ型の宣言を追加することで、指定のカラムにUNIQUE制約を付与することができます。
    以下にINSERT/SELECTサンプルをベースに、addressおよび、firstName+lastNameにUNIQUE制約を付与したサンプルコードを掲載しておきます。UNIQUE制約に関連する処理のみコメントで説明を加えています。

    
    {-# LANGUAGE EmptyDataDecls    #-}
    {-# LANGUAGE FlexibleContexts  #-}
    {-# LANGUAGE GADTs             #-}
    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE QuasiQuotes       #-}
    {-# LANGUAGE TemplateHaskell   #-}
    {-# LANGUAGE TypeFamilies      #-}
    import Control.Monad.IO.Class  (liftIO)
    import Database.Persist
    import Database.Persist.Sqlite
    import Database.Persist.TH
    
    share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
    Person
        firstName String -- nameをfistNameと
        lastName String  -- lastNameに分解
        age Int Maybe
        address String  -- addressカラム(VARCHAR)を新たに追加
        Address address -- addressカラムをUNIQUE制約に(先頭大文字でAddressを宣言)
        PersonName firstName lastName -- firstName, lastNameの組合せをUNIQUE制約に
        deriving Show
    |]
    
    main :: IO ()
    main = runSqlite ":memory:" $ do
        runMigration migrateAll
    
        -- addressも引数に追加。bobのデータも登録してみる。
        let michaelAddress = "1-2 xx Tokyo"
        michaelId <- insert $ Person "Michael" "Snoyman" (Just 26) michaelAddress
        bobId <- insert $ Person "Bob" "Marley" (Just 29) "2-20 yyy Hokkaido"
    
        -- UNIQUE制約フィールドは getBy で SELECTがかけられる
        bob <- getBy $ Address "2-20 yyy Hokkaido"
        -- bob の情報を表示。
        liftIO $ print bob
    
        -- PersonNameでもSELECTが可能。fistName, lastNameを渡してインスタンスを生成
        michael <- getBy $ PersonName "Michael" "Snoyman"
        liftIO $ print michael
    
        -- 登録されていないAddressでSELECTするとNothingが返される
        fail <- getBy $ Address "123-456 Fukuoka"
        liftIO $ print fail
    
        -- UNIQUE制約に違反するレコード(Michaelと重複)を登録しようとするとエラーになる
        markId <- insert $ Person "Mark" "Twain" (Just 29) michaelAddress
        -- エラー出力:
        -- uniqueness: user error (SQLite3 returned ErrorConstraint while attempting to perform step.)
        mark <- get markId
        liftIO $ print mark
    
    


    参考にしたサイト



    2014年8月23日土曜日

    [emacs][cygwin][mac] cygwin及びmac環境へのcmigemoのインストール

    cmigemoという便利なツールあることを知って、Windows(cygwin)とmacにインストールしました。cmigemoを利用することで、emacsのI-searchでひらがな・カタカナ・漢字を検索できるようになり非常に便利です!
    例えば、C-sもしくはC-rに続き"kara"を入力すると、メインバッファ中の「から」「」「(からす)」「カラオケ」「karaoke」「小」がインクリメンタルサーチにかかります。

    cygwinでのインストール手順

    • Cygwin SetupからC/Migemoのビルドに必要なパッケージをインストール
      • cygwinディレクトリのsetup_x64_64.exe(setup_x64.exe)を起動し、以下のパッケージを選択、インストールします。
        • Devel
          • gcc
          • make
        • Libs
          • libiconv
        • Web
          • wget
    • qkcのインストール
      • QKC Home Pageから"For UNIX"版のzipアーカイブをダウンロードしてインストールします。
      • 
        % unzip qkcc100.zip
        % make
        % cp qkc.exe /usr/local/bin
        
        
    • cmigemoのインストール
      • 以下のコマンドを実行することでインストールできます。オフィシャルな手順はcmigemo/doc/README_j.txtに記載されています。
      • 
        % git clone https://github.com/koron/cmigemo.git
        % cd cmigemo
        % ./configure
        % make cyg
        % make cyg-dict
        % make cyg-install
        
        
      • ./configureで"$'\r': コマンドが見つかりません"というエラーが出る場合はこちらを参考にしてエラーを回避してください。
      • 最後のmake cyg-installの実行で/usr/local以下に関連ファイルがコピーされます。アンインストールしたい場合にはmake cyg-uninstallを実行してください。
        • <要確認>インストールには管理者権限が必要(管理者権限を付与したターミナル上で実行)?
    • migemo.elのインストール
      • emacsを起動し以下のコマンドを実行
      • 
        M-x package-refresh-contents
        M-x package-install migemo
        
        
      • .emacsに以下のコードを追加
      • 
        (require 'migemo)
        (setq migemo-command "cmigemo")
        (setq migemo-options '("-q" "--emacs"))
        ;; Set your installed path
        (setq migemo-dictionary "/usr/local/share/migemo/utf-8/migemo-dict")
        (setq migemo-user-dictionary nil)
        (setq migemo-regex-dictionary nil)
        (setq migemo-coding-system 'utf-8-unix)
        (load-library "migemo")
        (migemo-init)
        
        

    macでのインストール手順

    • cmigemoのインストール
      • 以下のコマンドを実行することでcmigemoをインストールできます。デフォルトでインストールされているnkf, iconvが利用されるため、cygwinで行ったセットアップは不要です。
      • 
        % git clone https://github.com/koron/cmigemo.git
        % cd cmigemo
        % ./configure
        % make osx
        % make osx-dict
        % sudo make osx-install
        
        
      • デフォルトのインストール先は/usr/localになります。/usr/local/bin, /usr/local/libがPATH, LD_LIBRARY_PATHに設定されていない場合にはこれらを追加する必要があります。
    • migemo.elのインストール
      • emacsを起動し以下のコマンドを実行
      • 
        M-x package-refresh-contents
        M-x package-install migemo
        
        
      • .emacsに以下のコードを追加。utf8を利用する設定が紹介されておりcygwin環境ではそれを用いましたが、自分のmac環境ではutf8では後述の問題が出たためeuc-jpを設定しています。
      • 
        (require 'migemo)
        (setq migemo-command "cmigemo")
        (setq migemo-options '("-q" "--emacs"))
        ;; Set your installed path
        (setq migemo-dictionary "/usr/local/share/migemo/euc-jp/migemo-dict") ; macではutf8はNG?
        (setq migemo-user-dictionary nil)
        (setq migemo-regex-dictionary nil)
        (setq migemo-coding-system 'euc-jp) ; macではutf8はNG?
        (load-library "migemo")
        (migemo-init)
        
        
    • (補足)macではutf8の設定では正しくI-searchできない?
      • cygwinと同じ手順で「mac環境でも幸せ〜」になる予定だったのですが、アルファベットのI-searchができず不幸せな状態になってしまいました。問題の状況は"compile"を検索しようとして"co"をI-searchで入力しても検索に失敗してしまう、という状態でした。ミニバッファには以下のような情報が出力されています。"compi"まで入力すれば検索できる状態になります。
        • [MIGEMO] I-search: co [incomplete input]
      • この情報を見つけて以下のコマンドを実行してみましたが状況は改善せず。
        • M-x migemo-pattern-alist-clear
      • 試行錯誤した結果、エンコードをutf8からeuc-jpに変更すると正しく動作するようになったため、現状はこの設定で利用しています。

    参考

    [cygwin] 改行コードにCR+LFが用いられているスクリプトを実行する手順

    キャリッジリターン(CR, コードは0x0d)が改行コードとして用いられているスクリプトファイルをcygwin上で実行しようとすると、以下のようなエラーになります。
    
    ./configure: line 16: $'\r': コマンドが見つかりません
    
    

    ネット上で解決方法を探してみたところ、.bashrcで以下の設定をしておけばよいとのこと。
    
    export SHELLOPTS
    set -o igncr
    
    

    ところが自分のcygwin環境ではシェルにtcshを用いているために、上記の対応では問題を解決できませんでした。tcsh上でファイル先頭に
    
    #!/bin/sh
    
    
    が記載された、bash/shのスクリプトを起動したタイミングではホームディレクトリの.bashrcはロードしてくれないようです。/etc/bash.bashrc, ~/.startxwinrcに設定をいれてみても状況は改善せず…。
    最終的に/etc/profileにSHELLOPTSの設定を入れることで、意図した動作になりました。

    参考

    2014年7月23日水曜日

    [emacs][haskell] anything.elとauto-install.elのインストールとhaskell関連の設定

    emacsにanything.elをインストールしたので、その手順を残しておきます。package.elではanything.el本体とプラグインを一緒にインストールしてくれない、という情報があったので、auto-install.elを用いてインストールしました。

    ローカル環境にはauto-install.elが未インストールだったため、auto-install.elのセットアップから。

    auto-install.elのインストール

    1. emacs上でM-x package-list-packagesでパッケージ一覧を表示
    2. パッケージリスト中のauto-installの行で[i]でインストール対象に選択し、[x]でインストール実行
    3. .emacsに以下の記述を追加
    4. 
      (require 'auto-install)
      (auto-install-update-emacswiki-package-name t) ; EmacsWikiからパッケージ名を取得
      (add-to-list 'load-path "~/.emacs.d/auto-install")
      
      

    anything.elのインストール

    1. emacs上でM-x auto-install-batch anythingを実行
    2. 以下のファイルがDLされ、コンパイルするかどうかを効いてくるため全てに対してC-c C-c(コンパイル)を実行
      • anything-startup.el     
      • anything-ipa.el    
      • ipa.el    
      • anything-gtags.el    
      • anything-menu.el    
      • anything-grep.el    
      • descbinds-anything.el    
      • anything-auto-install.el   
      • anything-show-completion.el
      • anything-complete.el    
      • anything-obsolete.el    
      • anything-migemo.el    
      • anything-config.el    
      • anything-match-plugin.el   
      • anything.el
    3. .emacsに以下の記述を追加
    4. 
      (require 'anything-startup)
      
      

    haskell関連の設定

    1. haskell-modeのインストール
      1. M-x package-list-packagesでパッケージ一覧を表示しhaskell-modeを選択([i])し、インストール実行([x])。
      2. .emacsに以下の設定を追加
      3. 
        (require 'haskell-mode)
        (require 'haskell-cabal)
        (add-to-list 'auto-mode-alist '("\\.hs$" . haskell-mode))
        (add-to-list 'auto-mode-alist '("\\.lhs$" . literate-haskell-mode))
        (add-to-list 'auto-mode-alist '("\\.cabal\\'" . haskell-cabal-mode))
        (add-hook 'haskell-mode-hook (lambda () (turn-on-haskell-indent)))
        
        
        "turn-on-haskell-indentation"ではなく"trun-on-haskell-indent"を選択すること。"turn-on-haskell-indentation"だと[RET]にhaskell-newline-and-indentがバインドされ、リターンキー押下でデフォルトインデントしてしまう。newlineにマッピングしなおすと[TAB]によるインデントも効かなくなるため、インデントしない設定にできなかった…。
    2. ghc-modのインストール
      1. cabal install ghc-modでインストール
        1. ホームページからのインストール手順を参照
        2. M-x package-list-packagesでパッケージ一覧を表示しghc-modを選択([i])し、インストール実行([x])?
      2. .emacsに以下の設定を追加
      3. 
        (add-to-list 'load-path "~/Library/Haskell/ghc-7.6.3/lib/ghc-mod-3.1.7/share") 
        (autoload 'ghc-init "ghc" nil t)
        (autoload 'ghc-debug "ghc" nil t)
        (add-hook 'haskell-mode-hook (lambda () (ghc-init)))
        
        
    3. インストール済みパッケージの参照をanything.elで!
      1. こちらを参考に。
    4. auto-complete.elで補完!
      1. こちらを参考に。

    参考にしたサイト:

    2014年6月28日土曜日

    [windows] windows8.1セットアップメモ

    以前のwindows7セットアップメモに引き続き、windows8.1のセットアップメモを残しておきます。

    ウィンドウズ本体の設定

    • タスクバーとスタートメニューの設定
      • プロパティの「タスクバー」タブ
        • 「小さいアイコンを使う」にチェック
        • 「画面のタスクバーの位置」:タスクバーに入りきならない場合に結合
      • 「ナビゲーション」タブ
        • 「サインイン時または画面上のすべてのアプリを終了したときに、スタート画面ではなくデスクトップに移動する」にチェック
      • タスクバーに「クイック起動」を追加する
        • こちらの手順を参考に
        • ここに書かれている手順もわかりやすい。
      • エクスプローラー起動時のデフォルト表示パスを「お気に入り」に設定する
        • 以下のコマンドをリンク先に指定。
          • explorer.exe shell:::{323CA680-C24D-4099-B94D-446DD2D7249E}
        • ここの手順を参考に。
    • エクスプローラの設定
      • ごみ箱のプロパティ
        • 「ゴミ箱にファイルを移動しないで、削除と同時にファイルを消去する」を選択
        • 「削除の確認メッセージを表示する」にチェック
      • フォルダーオプション
        • 全般タブ
          • 「お気に入りを表示する」をアンチェック
          • 「すべてのフォルダーを表示する」にチェック
          • 「自動的に現在のフォルダーまで展開する」にチェック
        • 表示タブ
          • 「タイトルバーにファイルのパス名を表示する」にチェック
          • 「隠しファイル、隠しフォルダー、または隠しドライブを表示する」を選択
          • 「空のドライブは表示しない」をアンチェック
          • 「登録されている拡張子は表示しない」をアンチェック
          • 「保護されたオペレーティングシステムファイルを表示しない」をアンチェック
    • システム(操作・視覚効果)の設定


    アプリケーションのインストール

    • Google Chrome
    • KeySwap
      • 以下の3項目の設定で幸せになれる。
        • 「caps lock」キーと「左ctrl(1D)」キーの入れ替え
        • 「変換」キーと「全角/半角(29)」キーの入れ替え
        • 「全角/半角」キーと「Esc(01)」キーの入れ替え
      • ※ユーザーごとの設定はできない模様・・・。システム共通設定になります。
    • DF
      • ファイル比較ソフト
    • Stirling
      • バイナリエディタ
    • 秀丸
    • Lingoes
      • ネットに依存しない辞書
      • [CTRL]+右クリックで任意アプリ上の単語の意味をポップアップ表示
    • 7-Zip
      • 圧縮/解凍(展開): 7z, XZ, BZIP2, GZIP, TAR, ZIP, WIM
      • 解凍(展開)のみ: ARJ, CAB, CHM, CPIO, CramFS, DEB, DMG, FAT, HFS, ISO, LZH, LZMA, MBR, MSI, NSIS, NTFS, RAR, RPM, SquashFS, UDF, VHD, WIM, XAR, Z

    cygwinの設定&追加パッケージ

    • <<設定>>
    • ssh-agentの重複起動を防ぐ
        • /etc/passwdを編集する
      • ssh-agentのために秘密鍵セットアップ
        • ~/.ssh/
        • ※group/otherの権限は削除
    • <<環境変数>>
      • HOME
        • ホームディレクトリを切り替えられる
      • SHELL
        • "/bin/tcsh"とすることでデフォルトのシェルが切り替わる
    • <<インストールするパッケージ>>
    • Archive
      • bzip2
      • p7zip
      • unzip
      • zip
    • Database
      • mysql
      • postgresql-client
      • sqlite3
    • Devel
      • autoconf
      • automake
      • bashdb
      • binutils
      • ctags
      • dmalloc
      • doxygen
      • gcc
      • gdb
      • git
      • gitk
      • jlint
      • make
      • mercurial
      • ocaml
      • patch
      • patchutils
      • subversion
    • Doc
      • cygwin-doc (libc関連man page)
    • Editors
      • emacs
      • emacs-X11
      • vim
    • Libs
      • libiconv
      • libncurses-devel
    • Net
      • curl
      • inetutils  (telnet)
      • openssh
      • openssl
    • Web
      • ping
      • wget
      • wput
    • Ruby
      • ruby
      • ruby-sqlite3
    • Shells
      • rxvt-unicode
      • tcsh
      • xterm
    • Text
      • enscript
    • Utils
    • X11
      • xhost
      • xmodmap
      • xinit
      • xorg-server

    参考:

    2014年6月16日月曜日

    [haskell][yesod] YesodでFacebookのOAuth認証とつなぐ手順

    Yesodチュートリアルのサンプル(Yosog)には予め認証(auth)のコードが含まれており、/auth/loginでGoogleEmailとBrowserIdによる認証が可能になっています。今回、そのチュートリアルサンプルをFacebookのOAuth認証とつなげることができたのでその手順とコードを紹介しておきます。

    Facebookの設定

    FacebookのOAuth認証を利用するには、認証を利用するアプリケーションをFacebookのdevサイトに予め登録しておく必要があります。手順は以下の通りです。
    1. アプリを登録してApp IDとSecretを得る
      1. facebookの開発者サイトにログイン
      2. 「アプリ」-「 新しいアプリを作成する」で必要項目を入力
    2. ログイン後のページ遷移ができるようにサイトURLを設定しておく
      1. 新たに登録したアプリの設定ページで「基本データ」タブを開く
      2. [Add Platform]を選択し一覧から「ウェブサイト」を選択
      3. 表示された設定項目中の「サイトURL」に起動するweb appのURLを登録
        • ローカルで起動したサーバーを用いて動作確認する際いは以下のURLを設定しておく
        • http://localhost:3000/

    チュートリアルのコードの変更

    まずここを参考にチュートリアルサンプルが動作する環境を整えてください。http://localhost:3000/で"Hello"画面が出ていればOKです。http://localhost:3000/auth/loginにアクセスすると、GoogleEmail/BrowseIdによる認証画面が表示されます。この状態で以下の変更を加えるとFacebook認証を利用することができます。
    1. Foundation.hsの変更
      1. importに以下のモジュールを追加
      2. 以下の3行を追加します。
        
        import Yesod.Facebook (YesodFacebook(..))
        import Yesod.Auth.Facebook.ServerSide
        import Facebook (Credentials(..))
        
        
      3. authPluginsをFacebookに書き換える
      4. 既存のBrowserId, GoogleEmailの宣言をFacebookのものに書き換えます。
        
            authPlugins _ = [authBrowserId def, authGoogleEmail]
            authPlugins _ = [authFacebook ["email"]]
        
        
      5. Facebook.Credentialの追加
      6. 以下のコードを追加します。前述のFacebookの設定によって得られるApp IDとApp Secretをそれぞれ、Facebook.Credentialの第2、第3引数に指定します。
        
        instance YesodFacebook App where
            fbCredentials _ = Facebook.Credentials "Yesod FB Auth Sample" "012345678901234" "aaaaaaaabbbbbbbbccccccccdddddddd"
            fbHttpManager = httpManager
        
        
    2. Yosog.cabalに依存ライブラリを追加する
    3. Yosog.cabalをエディタで開き、build-dependsに以下の3つのライブラリを追加します。
      
                       , yesod-fb
                       , yesod-auth-fb
                       , fb
      
      
    4. HomeRの変更(省略可能)
    5. Handler/Home.hsのgetHomeRのコードを以下のように編集することで、http://localhost:3000/の挙動をAuthentication and AuthorizationAuthenticate Meサンプルと同じ挙動にすることができます。
      
      import           Yesod.Auth
      
      getHomeR :: Handler Html
      getHomeR = do
      
          maid <- lookupSession "_ID"
          defaultLayout
              [whamlet|
                  <p>Your current auth ID: #{show maid}
                  $maybe _ <- maid
                      <p>
                          <a href=@{AuthR LogoutR}>Logout
                  $nothing
                      <p>
                          <a href=@{AuthR LoginR}>Go to the login page
              |]
      
      
    これでFacebookのOAuth認証が利用可能になります。ブラウザを起動してhttp://localhost:3000/auth/loginにアクセスしてください。ブラウザ上に"Login with Facebook"というリンクが表示されるはずです。そのリンクをクリックするとFacebookのサイトにジャンプしてアプリケーションの認証が促されます。そこでOKを選択すると、ログイン状態に遷移します。
    動作確認に用いたコードはgithubにアップしました。

    参考にしたサイト:

    2014年6月7日土曜日

    [mac] macにインストールしているソフトウェア

    自分のmac環境にインストールしているアプリ・ツールをリストアップしておきます。
    • Google Chrome
      • 言わずと知れたgoogle製ブラウザ
    • MacPorts
      • mac版のパッケージ管理システム(yum,rpmの代わり)
      • インストールしているパッケージ:
        • autoconf
        • automake
        • curl
        • emacs-mac-app
        • emacs (for emacsclient)
        • enscript
        • fish
        • gcc*
        • gdb
        • global (gtags for emacs)
        • gnupg
        • gperf
        • lv
        • man
        • openssh
        • postgresql
        • python
        • ruby*
        • sqlite3
        • subversion
        • wget
      • *: 複数バージョンが存在するパッケージの切り換え方法はこちらを参照
    • Haskell Platform
    • Carbon Emacs
      • emacs21で古い…
      • MacPortsのemacs-mac-appがemacs24なので乗り換えた
    • XQuartz
      • mac版のX Window System
    • DiffMerge
      • GUI版ファイル比較アプリケーション
    • VirtualBox / Genymotion
      • mac上で日本語のkindle版書籍を読める。
      • 最新バージョンでは削除されているが、旧バージョンのGenymotionではgoogle application入りのパッケージが配布されていた…。
    • SourceTree
      • GUI版git/Mercurialクライアントアプリケーション
    • DropBox
    • Karabiner(旧 KeyRemap4MacBook
      • キーアサインを自由に変更
      • Emacs Mode
        • Control+PBF to Up/Down/Left/Light (+ many more)
        • Control+V to PageDown
        • Command+V to PageUp
        • Control+Y to Command+V
        • Control+W to Command+X
        • Control+/ to Command_Z
        • Control+S to Command+F
      • For Japanese
        • Change EISUU Key -> EISUU to Command_L
        • Change KANA Key -> Use KANA/EISUU (toggle)
        • Change Yen(¥) Key -> JIS Yen(¥) to Backslash (\)
    • TinkerTool
      • 各種隠し設定
    • AppCleaner
    • ClipMenu
      • クリップボード履歴
    • AppStore経由
      • Evernote
      • Xcode
      • Skitch(画面キャプチャ、簡易編集)
      • Dash(Instant search & offline access to any API documentation) 
    2015/02/07現在、上記のような感じです。
    今後もメンテナンス予定。

    ソフトウェア開発に関するおすすめツール・アプリ、お知らせいただけるとうれしいです。

    2014年5月12日月曜日

    [linux] ソースコードをHTMLに変換するコマンド:enscript

    ブログ上でコードを紹介する際、単にコードをコピペしただけだと"<", ">", "&"などの文字が適切に表示されなかったり、タブの位置がずれたり、キーワードがわかりにくかったり、といった問題に遭遇します。
    いろいろとツールが出ているようなのですが、linux上であればenscriptというコマンドで容易にhtml化ができることが分かったためその方法を紹介します。

    
    %  enscript --highlight=cpp --color -C -o output.html -w html input.cpp
    
    

    上記のコマンドでinput.cppの内容がoutput.htmlに出力されます。キーワードをハイライトするオプションである"--color"を指定する際には"--hilight"が必要なので注意が必要です。また、行番号を出力する"-C"はhtmlへの出力時には効かないようです(残念…)。
    入力としてサポートしている言語は多岐にわたっています。以下、そのリストになります。
    • ada
    • asm
    • awk
    • bash
    • c
    • changelog
    • cpp
    • csh
    • delphi
    • diff
    • diffs
    • diffu
    • elisp
    • f90
    • fortran
    • fortran_pp
    • haskell
    • html
    • idl
    • inf
    • java
    • javascript
    • ksh
    • m4
    • mail
    • makefile
    • matlab
    • nroff
    • objc
    • outline
    • pascal
    • perl
    • postscript
    • pyrex
    • python
    • rfc
    • ruby
    • scheme
    • sh
    • skill
    • sql
    • states
    • synopsys
    • tcl
    • tcsh
    • tex
    • vba
    • verilog
    • vhdl
    • vrml
    • wmlscript
    • zsh
    "-w"で指定する出力フォーマットは以下の通りです。
    • PostScript
      • generate PostScript (default)
    • html
      • generate HTML
    • overstrike
      • generate overstrikes (line printers, less)
    • rtf
      • generate RTF (Rich Text Format)
    • ansi 
      • generate ANSI terminal control codes

    (独り言…)haskellもサポート言語に加えてほしいなぁ。失礼しました。ちゃんとhaskellもサポートされていました。

    [c++][gcc] constメンバ関数の中でメンバ変数を書き換えるには

    C++において、一般的に定数宣言の目的で使用されるconst修飾子ですが、メンバ変数、メンバ関数、引数、返値にも宣言できることはご存知でしょうか。
    適切に利用することで、以下のようなメリットが得られます。
    • API仕様がより明確になる
    • コードの可読性・メンテナンス性があがる

    これらのメリットを享受すべくconst修飾子を積極的に利用していたのですが、まれにconstメンバ関数の中で、メンバ変数を書き換えたい、もしくは、メンバ変数の関数を呼び出したい、といったケースが発生したことがありました。
    これまではconst関数の中でメンバ変数の値は参照のみで書き換えはできないと思っていたのですが「C++のためのAPIデザイン」という書籍を読みmutable修飾子が用意されていることを知りました。

    const関数の中でメンバ変数を書き換えようとすると以下のようなエラーになります。
    
    const_test.cpp: In member function 'void ConstTest::constFunc(int) const':
    const_test.cpp:11:9: error: assignment of member 'ConstTest::m_val' in read-only object
       m_val = val;
             ^
    const_test.cpp:12:23: error: passing 'const NotConst' as 'this' argument of 'void NotConst::normalFunc()' discards qualifiers [-fpermissive]
       m_normal.normalFunc();
                           ^
    
    これは以下のコードをコンパイルしたときのエラーです(gcc 4.8.2)。
    class NotConst
    {
    public:
     void normalFunc() /*const*/ {}
    };
    class ConstTest
    {
    public:
     void constFunc(int val) const
     {
      m_val = val;
      m_normal.normalFunc();
      return;
     }
    private:
     /*mutable*/ int m_val;
     /*mutable*/ NotConst m_normal;
    };
    
    15行目と16行目でコメントアウトしているmutable修飾子を有効にすると、エラーなくコンパイルが通るようになります。mutable修飾子が付与されている変数を見かけたときには「const宣言されたオブジェクトでも変更されることがありますよ」と理解しましょう。

    ちなみに後者のエラーは、NotConst::normalFunc()をconst関数に変更することでも修正が可能です。normalFunc()の仕様としてconst関数が適切なのであれば、mutable宣言を用いるのは避けてconst関数化すべきです。

    2014年3月30日日曜日

    [mac][haskell] Marvericksにアップグレードするとsys/cdefs.hが見つからなくなる問題の対処

    Mac OS Xを10.8(Mountain Lion)から10.9(Marverhicks)にアップグレードしたところ、cabal installでパッケージをインストールしようとすると、以下のようなエラーが出る状態になってしまいました。
    
         fatal error: sys/cdefs.h: No such file or directory
         #include <sys cdefs.h>
                               ^
    compilation terminated.
    
    

    これはアップグレードにより、xcodeのコマンドラインツールによってインストールされていた/user/include以下のファイルが削除されていたために、sys/cdefs.hが見つからず、エラーになっていたようです。
    ここの情報を参考にして、以下のコマンドでxcode5のコマンドラインツールをインストールすることで、sys/cdefs.hが配置されエラーは発生しなくなりました。
    
    % xcode-select --install
    
    

    なお、Haskell Platformのインストール手順に記載されているghc-clang-wrapperなるものも必要なのでお忘れなく。

    2014年3月13日木曜日

    [heroku][yesod] Heroku上でSQLiteを使ってはいけない

    HerokuでSQLiteを使ってはいけない理由

    なぜHerokuでSQLiteを使ってはいけないか。理由は以下の2つです。
    • HerokuのCedar Stackはephemeral filesystemを持っており、一見ファイルの読み書きができるように見えるが、一日に一度すべてクリアされる。このためSQLiteで保存したデータも毎日失われてしまう。
    • もしHerokuのファイルシステムが永続的にデータを保持したとしても別の問題がある。SQLiteはサービス機能を持っていないため各dynoの間でデータを共有することができず、それぞれ固有のDBを保持しているように振る舞ってしまう。
    HerokuサイトのLearning - Application Architectureで公開されているSQLite on Herokuに詳細が説明されています。SQLiteの代わりにアドオンで提供されているPostgreSQL、MySQL、MongoDBなどを使うことになります。
    今回YesodチュートリアルのYosogアプリで利用するデータベースをSQLiteからPostgreSQLに移行しました。その手順を紹介しておきます。

    ローカル(mac)環境でのPostgres対応

    まずローカル環境で動作しないことにはサーバ上で動作するはずがない、ということで、mac上のDevelopment環境でPostgreSQLを利用する手順を記載しておきます。
    Yesodチュートリアルのサンプル(Yosogアプリ)をローカル環境でPostgreSQL上で動作させるには以下の修正が必要でした。yesod initコマンド実行時に利用DBとしてsqliteでなくpostgresqlを選択すれば、ここで述べるのSQLiteからPostgreSQLへの変更手順は不要になります。
    1. SQLite環境をPostgreSQL環境に変更
      1. Application.hsのdbconfをSQLiteからPostgreSQLに
      2. 
        -     dbconf <- withYamlEnvironment "config/sqlite.yml" (appEnv conf)
        +     dbconf <- withYamlEnvironment "config/postgresql.yml" (appEnv conf)
        
        
      3. Settings.hsのPersistentConfをSQLiteからPostgreSQLに
      4. (その1)
        
        -import Database.Persist.Sqlite (SqliteConf)
        +import Database.Persist.Postgresql (PostgresConf)
        
        
        (その2)
        
        -type PersistConf = SqliteConf
        +type PersistConf = PostgresConf
        
        
      5. Yosog.cabalのbuild-dependsをpersistent-sqliteからpersistent-postgresに
      6. (その1)
        
        -                 , persistent-sqlite             >= 1.3        && < 1.4
        +                 , persistent-postgresql         >= 1.3        && < 1.4
        
        
        (その2)
        
        -                 , persistent-sqlite
        +                 , persistent-postgresql
        
        
      7. config/postgresql.ymlの準備
      8. 
        Default: &defaults
          user: Yosog
          password: Yosog
          host: localhost
          port: 5432
          database: Yosog
          poolsize: 10
        
        Development:
          <<: *defaults
        
        Testing:
          database: Yosog_test
          <<: *defaults
        
        Staging:
          database: Yosog_staging
          poolsize: 100
          <<: *defaults
        
        Production:
          database: Yosog_production
          poolsize: 100
          <<: *defaults
        
        
    2. MacPortsでpostgresql93をインストールする
      1. postgresql93パッケージをインストール
      2. 
        % sudo port install postgresql93
        % sudo port install postgresql93-server
        % sudo port select postgresql postgresql93
        
        
      3. DBインスタンスの生成(serverのinstall時の指示に従う)
      4. 
        % sudo mkdir -p /opt/local/var/db/postgresql93/defaultdb
        % sudo chown postgres:postgres /opt/local/var/db/postgresql93/defaultdb
        % sudo su postgres -c '/opt/local/lib/postgresql93/bin/initdb -D /opt/local/var/db/postgresql93/defaultdb' 
        
        
      5. サーバーの起動
      6. 
        % sudo launchctl load -w /Library/LaunchDaemons/org.macports.postgresql93-server.plist
        % sudo launchctl start org.macports.postgresql93-server
        
        

    3. Yosogアプリが利用するDBを生成する
      1. ユーザーとデータベースの生成
      2. 自動生成されるconfig/postgres.ymlを確認するとYosogユーザーでYosogデータベースにアクセスする設定になっています。このため以下のコマンドでユーザーとデータベースを作成しておきます。
        
        % createuser -U postgres -P Yosog
        % createdb -U postgres Yosog
        
        
        ユーザーとデータベースが作成されていないと、Yosogアプリ起動時に以下のエラーになります。
        
        Yosog: SqlError {sqlState = "", sqlExecStatus = FatalError, sqlErrorMsg = "FATAL:  role \"Yosog\" does not exist\n", sqlErrorDetail = "", sqlErrorHint = ""}
        
        
      3. PostgreSQL対応したYosogアプリの起動
      4. 
        % cabal run -- Development
        
        

    HerokuにPostgreSQL対応版Haskell/Yesodアプリをdeployする

    PostgreSQLを利用する手順はRuby on Rails上であればHerokuのドキュメントで紹介されています。ここではHaskellのYesodフレームワーク上でPostgreSQLを利用するサーバーをHerokuにデプロイするための手順を示しておきます。
    1. postgresqlアドオンの登録&接続情報の確認
      1. postgresqlアドオン登録
      2. 
        %  heroku addons:add heroku-postgresql:dev
        
        
      3. DB情報の確認
      4. 
        % heroku pg:info
        === HEROKU_POSTGRESQL_IVORY_URL
        Plan:        Dev
        Status:      available
        Connections: 0
        PG Version:  9.3.3
        Created:     2014-03-12 15:42 UTC
        Data Size:   6.4 MB
        Tables:      0
        Rows:        0/10000 (In compliance)
        Fork/Follow: Unsupported
        Rollback:    Unsupported
        
        
      5. 接続情報の確認
      6. 
        % heroku pg:credentials HEROKU_POSTGRESQL_IVORY_URL
        Connection info string:
           "dbname=ddddd host=aaa-11-222-33-44.compute-1.amazonaws.com port=5432 user=uuuuu password=XXXXX sslmode=require"
        Connection URL:
            postgres://uuuuu:XXXXX@aaa-11-222-33-44.compute-1.amazonaws.com:5432/ddddd
        
        
    2. 接続情報の反映と接続確認
      1. config/postgresql.ymlの編集
      2. 接続情報で確認した、dbname, host, user, passwordをpostgresql.ymlのProduction:の設定に反映します。
        
        --- a/config/postgresql.yml
        +++ b/config/postgresql.yml
        @@ -19,6 +19,10 @@ Staging:
           <<: *defaults
         
         Production:
        -  database: Yosog_production
        +  user: uuuuu
        +  password: XXXXX
        +  host: aaa-11-222-33-44.compute-1.amazonaws.com
        +  port: 5432
        +  database: ddddd
           poolsize: 100
           << *defaults
        
        
      3. postgresql対応版サーバーのdeploy
      4. 
        % git commit -m "- use postgersql instead of sqlite." .
        % git push heroku master
        % heroku open
        
        
      5. psqlを用いた接続確認(おまけ)
      6. 以下のコマンドでPCからadonしたPostgreSQLのDBに接続することができます。postgresql.ymlのDevelopment:欄に同様の設定をすればアプリ本体はPC上、DBはサーバー上の組み合わせで動作確認することもできます。
        
        % psql -h aaa-11-222-33-44.compute-1.amazonaws.com -p 5432 -U uuuuu DDDDD
        ddddd> \d
                          List of relations
         Schema |      Name      |   Type   |     Owner      
        --------+----------------+----------+----------------
         public | article        | table    | uuuuu
         public | article_id_seq | sequence | uuuuu
         public | email          | table    | uuuuu
         public | email_id_seq   | sequence | uuuuu
         public | user           | table    | uuuuu
         public | user_id_seq    | sequence | uuuuu
        (6 rows)
        
        

    ここまでの修正はGitHubにコミット済みです。
    https://github.com/kurokawh/Yosog/tree/Yosog_PostgreSQL
    メモ:ローカルリポジトリの変更をリモートのmaster以外の別ブランチにプッシュするには、以下のコマンドを実行する。
    
    % git push origin master:Yosog_PostgreSQL
    Counting objects: 24, done.
    Delta compression using up to 4 threads.
    Compressing objects: 100% (18/18), done.
    Writing objects: 100% (18/18), 2.02 KiB | 0 bytes/s, done.
    Total 18 (delta 12), reused 0 (delta 0)
    To https://kurokawh@github.com/kurokawh/Yosog.git
       be68e29..8a25b29  master -> Yosog_PostgreSQL
    % git branch -r
      origin/Yosog_PostgreSQL
      origin/master
    
    

    参考にした情報:

    2014年3月11日火曜日

    [cygwin][linux] tcshのデフォルト補完設定のイマイチな部分を修正しよう

    cygwinや最近のlinuxディストリビューション上でtcshを起動すると、デフォルトでたくさんの補完設定がされていて便利なのですが、局所的に自分の使い方とマッチしない設定があるのでそれを修正します。
    cygwinでは/etc/profile.d/complete.tcshに、ubuntuでは/etc/complete.tcshにあるデフォルト設定ファイルを編集することになります。

    イケてない設定1:cpやmvの第二引数の補完対象がディレクトリに限定されている

    一番イケてないのがcp/mvのデスティネーション(第二引数)がディレクトリに限定されている点。上書き先に直接ファイルを指定したい、または複数ファイルをまとめてコピーしたい、といったケースで補完が効きません・・・。
    
        complete mv  c/--/"(backup force interactive update verbose suffix \
       version-control help version)"/ \
       c/-/"(b f i S u V v -)"/ \
       n/{-S,--suffix}/x:''/ \
       n/{-V,--version-control}/"(t numbered nil existing \
       never simple)"/ n/-/f/ N/-/d/ p/1/f/ p/2/d/ n/*/f/
    
        complete cp  c/--/"(archive backup no-dereference force \
           interactive link preserve parents sparse recursive \
       symbolic-link suffix update verbose version-control \
       one-file-system help version)"/ \
       c/-/"(a b d f i l P p R r S s u V v x -)"/ \
       n/-*r/d/ n/{-S,--suffix}/x:''/ \
       n/{-V,--version-control}/"(t numbered nil existing \
       never simple)"/ n/-/f/ N/-/d/ p/1/f/ p/2/d/ n/*/f/
    
    
    取り消し線で潰してある"p/2/d"を削除すれば所望の動作になります。ちなみに"p"は引数位置を指定するパターンコマンドで"2"が第二引数、"d"が(ファイルを除く)ディレクトリを意味しています。


    イケてない設定2:lnの第二・三引数で補完が効かない

    lnコマンド実行時"-s"オプションを指定の上、任意のディレクトリ・ファイルを第一引数に指定しますが、これが第二引数と解釈され、以下のような結果になります。
    % ln -s [CTRL-D]
    <link_name>
    
    取り消し線の"p/2/x:'<link_name>'"を"p/2/f/'"に置き換えれば第二・三引数で補完が効くようになります。
    % ln -s [CTRL-D]
        complete ln  c/--/"(backup directory force no-dereference \
           interactive symbolic suffix verbose version-control \
       help version)"/ \
       c/-/"(b d F f i n S s V v -)"/ \
       n/{-S,--suffix}/x:''/ \
       n/{-V,--version-control}/"(t numbered nil existing \
       never simple)"/ n/-/f/ N/-/x:'<link_name>'/ \
       p/1/f/ p/2/x:'<link_name>'/ p/2/f/ 
    
    


    イケてない設定3:gitコマンドが補完できない

    svnは対応されており、以下のようなコマンドが補完されるのですが、gitは登録されておらずコマンドを補完してくれません。
    
    % svn [CTRL-D]
    add      cleanup  export   list     merge    propedit resolved unlock
    blame    commit   help     lock     mkdir    propget  revert   update
    cat      copy     import   log      move     proplist status   
    checkout delete   info     ls       propdel  propset  switch   
    
    

    svnの設定をコピって以下の補完を追加。"@"は"/"と同じ意味です。
    
        complete git  'n@help@(add bisect branch checkoutclone \
                commit diff fetch grep init log merge mv \
       pull push rebase reset rm show status tag)@' \
       'p@1@(add bisect branch checkoutclone \
                commit diff fetch grep init log merge mv \
       pull push rebase reset rm show status tag)@'
     
    

    イケてない設定4:Haskell関連コマンドの補完が未登録

    ghc、ghci、cabalの補完設定も追加して幸せになりましょう。
    
        complete ghc  c/-v/"(0 1 2 3 4 5)"/ \
                c/-i/d/ \
                c/--/"(interactive make mk-dll help show-iface \
             supported-extensions supported-languages \
             info version numeric-version print-libdir)"/ \
       c/-W/"(all error warn)"/ \
       c/-{fwarn-,fno-warn-}/"(unrecognised-pragmas \
              warnings-deprecations deprecated-flags \
              unsupported-calling-conventions \
              dodgy-foreign-imports dodgy-exports \
              dodgy-imports lazy-unlifted-bindings \
              duplicate-exports hi-shadowing \
              identities implicit-prelude \
              incomplete-patterns incomplete-uni-patterns \
              missing-fields missing-import-lists \
              missing-methods missing-signatures \
              missing-local-sigs name-shadowing \
              orphans auto-orphans overlapping-patterns \
              tabs type-defaults monomorphism-restriction \
              unused-binds unused-imports unused-matches \
              unused-do-bind wrong-do-bind )"/ \
       c/-f/"(defer-type-errors helpful-errors \
              force-recomp warn- no-warn-)"/ \
        c/-/"(E C S c fglasgow-exts O prof H14m M e V w\
             ferror-spans ghc-timing fforce-recomp ?)"/ \
       n/-{odir,hidir,stubdir,dumpdir,outputdir,tmpdir}/d/ \
       'n/--make/f:*.hs/' \
        'n/*/f:*.hs/'
    
        complete ghci c/-i/d/ \
                c/-/"(fglasgow-exts H32m cpp i)"/
    
        complete cabal c/--{config-file,sndbox-config-file}=/f/ \
       c/--/"(help version numeric-version config-file= \
                      sandbox-config-file=)"/ \
       p/1/"(install update list info fetch get check \
            sdist upload report run init configure build \
            repl sandbox copy haddock clean hscolour \
            register test bench help)"/
    
    

    参考にしたサイト:

    2014年3月3日月曜日

    [heroku][yesod] YesodアプリをHeroku上にデプロイする手順

    YesodアプリをHeroku上にデプロイできました!以前にローカル環境で確認したYesodチュートリアルのwebアプリケーションをHeroku上で動作させることができたので、その手順をまとめておきます。

    前提環境:

    • Yesodチュートリアルのアプリケーション(Yesog)が動作している
    • gitがインストールされている
    • heroku toolbeltがインストールされている
    • 動作確認した環境の詳細
      • % ghc --version
        • The Glorious Glasgow Haskell Compilation System, version 7.6.3
      • % cabal --version
        • cabal-install version 1.18.0.2
        • using version 1.18.1.2 of the Cabal library 
      • % yesod version
        • yesod-bin version: 1.2.6
      • % heroku version
        • heroku-toolbelt/3.4.1 (x86_64-darwin10.8.0) ruby/1.9.3

    デプロイ手順:

    以下の手順を実行することでYosogアプリケーションをHeroku上にデプロイし、クライアントからアクセスできるようになります。
    1. Yosog.cabalをエディタで開き、以下の取り消し線部分の記述を削除する
    2. 
      
      executable         Yosog
      
          if flag(library-only)
              Buildable: False
      
          main-is:           main.hs
          hs-source-dirs:    app
          build-depends:     base
                           , Yosog
                           , yesod
      
      
      この記述があると、cabal runで以下のようなエラーが発生してしまいます。原因不明…。
      
      cabal: Cannot build the executable 'Yosog' because the component is marked as
      
      disabled in the .cabal file.
      
      
    3. YosogルートディレクトリにProfileを用意する
    4. 
      % echo "web: cabal run -- production -p $PORT" > Profile
      
      
      このファイルはHerokuがサーバーを起動する手順になります。ローカル環境でも同様のコマンドでサーバーが起動することを確認しておきましょう。
    5. gitリポジトリにファイルを登録
    6. 
      % git init .
      % git add *
      % git commit -m "Initial commit." .
      
      
    7. heroku上にアプリケーションを登録
    8. 
      % heroku create --stack=cedar --buildpack https://github.com/begriffs/heroku-buildpack-ghc.git
      
      
    9. heroku上にアプリケーションをデプロイ
    10. 
      % git push heroku master
      
      
      10分くらい時間がかかります。状況によっては15分のビルド時間制限をオーバーしてしまうこともあるようです。そのようなときには、以下の手順で別サーバーでビルドを実行することができる模様。
      
      % heroku plugins:install https://github.com/ddollar/heroku-anvil
      % heroku build -r -b https://github.com/begriffs/heroku-buildpack-ghc.git
      
    以上です。
    heroku open
    上記のコマンドでパブリックなサーバーとして起動しているYosogアプリケーションにアクセスすることができます。GitHubでこの環境をを公開しておきます。

  • https://github.com/kurokawh/Yosog.git
  • 参考情報:

    以下、参考にした情報についてまとめておきます。複数サイトの情報を参照しつつ作業したのですが、自分の環境ではうまくいかなかった手順もありました。最終的に最も成功に近かった手順は以下のサイトの情報になります。
    以下のサイトの情報も試しましたが、いずれもクライアントからアクセスできる状態にたどりつけませんでした。
    • Haskell Buildpack Demo
      • サンプルのデプロイ、動作確認は成功。だが、自環境のYosogアプリについては、deployまで成功したが、heroku openを実行してもサーバーとは繋がらず…。
    • MacでHerokuにYesodを(Herokuに公開編)
      • この手順はバイナリをgitコミットして、コンパイルなしてサーバー上で起動する手順だと思われます。mac上でビルドしたバイナリはdeployまではできるものの、heroku openで繋がりませんでした。

    その他、新たに学習した情報のメモ

    いろいろはまったことで、自分にとっての新しい知識が少しだけ増えました。Herokuへのデプロイと直接は関係しませんが、それらもまとめておきます。
    • yesodアプリをリリースビルドする手順
      • scafoldsiteではyesod develでビルド&テストサーバーが起動されますが、リリース用のバイナリを生成するには
        • cabal install
      • を実行することになります。このコマンドを実行すると
        • dist/dist-sandbox-5ba8a016/build/Yosog/Yosog
      • が生成されます。production -p XXXという引数とともにこのバイナリを起動すると、プロダクション版のサーバーを起動できます。
        • dist/dist-sandbox-5ba8a016/build/Yosog/Yosog production -p 3000
    おわり。

    2014年3月1日土曜日

    [mac][haskell] Haskell Platformのアンインストール手順

    yesod-platformの更新を試みたところパッケージ間の依存関係に問題が発生してにっちもさっちもいかない状態になってしまいました。そこで不本意ではありますがHaskell Platform自体をゼロからクリーンインストールすることに。
    ところがHaskell Platformのインストール手順は本家のウェブサイトに記載されているのですが、アンインストールの手順が見あたりません。ネット上で見つかった「Haskell Platformをアンインストールして綺麗な環境を取り戻す」を参考に自分のmac環境からもクリーンアップできた(はず)なので、その手順を残しておきます。
    1. Haskell Platformのインストーラでコピーされたファイルを削除する
      • /Library/Frameworks/GHC.framework/Versions/Current/Tools/Uninstallerを実行する
        • (2015.10.24追記)Uninstallerファイルに実行権限がないのが原因でした。以下の通り実行できました。
        • % sudo chmod +x /Library/Frameworks/GHC.framework/Versions/Current/Tools/Uninstaller
          % sudo /Library/Frameworks/GHC.framework/Versions/Current/Tools/Uninstaller
          Removing /Library/Frameworks/GHC.framework/Versions/7.6.3-x86_64
          Removing /Library/Frameworks/GHC.framework
          Removing package receipt
          Done.
          
      • 自分の環境では、このスクリプトを実行するとcommand not foundというエラーになってしまったため、手動で/Library/Frameworks/GHC.framework/を削除しました。
      • 
        sudo rm -rf /Library/Frameworks/GHC.framework/
        sudo rm -rf /Library/Haskell/
        
        
    2. ユーザー環境にインストールされたパッケージ群を削除する
      • ~/Library/Haskell/以下を全て削除
      • 
        rm -rf ~/Library/Haskell/
        
        
    3. ホームディレクトリ直下の.ghc, .cabalを削除する
      • 
        rm -rf ~/.ghc ~/.cabal
        
        
    1.の手順をスキップするとHaskell Platformを再インストールした直後のクリーンな状態と同じ状態にできます。追加インストールしたパッケージ群だけを全てクリアしたい、という目的に対しては、2.と3.だけを実行するのがおすすめです。

    2014年2月5日水曜日

    [haskell] ubuntu 10.04 LTS (lucid) にhaskell platformをインストールする 手順

    herokuのサーバーに手元でビルドしたバイナリをデプロイする目的でUbuntu 10.04 LTS(lucid)環境を作りました。herokuの仮想サーバーと同じ環境をローカルに用意して、そこでビルドしたHaskellのバイナリをサーバー上で動作させよう、という魂胆です。

    必要なソフトウェアをapt-getでがしがしインストールしていったのですが、肝心のHaskellがghc6しか存在しません…。googleで検索してみるも、Ubuntu 11.x, 12.x向けであればghc7のパッケージが用意されているのですが、10.04向けのバイナリは見つからず。

    という状況で試行錯誤した末、以下の手順でHaskell Platform環境を構築することができました。
    1. The Glasgow Haskell CompilerのページからLinux_x86_64のバイナリをダウンロード&インストール
      • バイナリアーカイブをDL
      • sudo make install
    2. ここの情報を参考にHaskell Platformが依存するライブラリ群をapt-getでインストール
      • apt-get install libgmp-dev
      • apt-get install libgmp3c2
      • apt-get install zlib1g-dev
      • apt-get install freeglut3-dev
      • (libbsdは既にインストール済みだったためパス)
      • また、古いHaskell関連パッケージは削除
      • apt-get remove ghc6 ghc-prof cabal-install
    3. Haskell PlatformのサイトからソースコードをDLしてきて、ビルド&インストール
      • ./configure
      • make
      • sudo make install
    以上です。ghc6環境ではHaskell Platformのビルドができなかったため、1.の手順を実行しています。

    2014年2月2日日曜日

    [heroku] はじめてのheroku

    インターネット上の情報を参考にしながら、自分のMacにherokuを利用する上で最低限の環境を構築しrubyとHaskellのサンプルウェブアプリを動かしてみた。

    Mac上の準備:

    1. MacPortsをインストール(手順はここ
    2. portsでruby19をインストール(port install ruby19。こちらの手順で複数のバージョンを選択切り換えができます)
    3. heroku toolbeltをインストール(ここからインストーラをダウンロードして、インストール)
      • 以前はruby gemでherokuをインストールしていたようです(gem install heroku)

    ruby版サンプルサーバーのherokuへのデプロイ:

    
        % git clone git://github.com/heroku/ruby-sample.git
        % cd ruby-sample/
        % heroku create
        % git push heroku master
        % heroku open
    
    
    これだけで"Hello World!"が表示されるウェブアプリが動き始めた!ローカル環境にrailsもインストールしたのですが、heroku上でサーバーを動作させるだけであればrailsのインストールは不要でした。

     Haskell版サンプルサーバーのherokuへのデプロイ:

    ここの情報を参考にherokuのサンプルも動作した!
    
        % git clone https://github.com/pufuwozu/haskell-buildpack-demo.git
        % cd haskell-buildpack-demo/
        % heroku create --stack=cedar --buildpack https://github.com/pufuwozu/heroku-buildpack-haskell.git
        % git push heroku master
        % heroku open
    
    
    このサンプルではWarp(Haskell製ウェブサーバー)を直に利用している。 自分が利用しようとしているのはウェブアプリケーションフレームワークのYesod(内部でWarpを使用)なので、Heroku上でYesodを利用する方法は別途調査が必要。こちらにはsnap(yesodとは別のweb framework)のデプロイサンプルがある。
    Haskellのサーバーをheroku上で動作させる方法は、このサンプルのようにビルドパッケージを利用する方法以外に、あらかじめコンパイルしてgitリポジトリにコミットしたバイナリを動作させる方法もあるようなので、後者についても少し調べてみる予定。

    Yesodのチュートリアルサンプルのデプロイ:

    試しに、昨年末にローカルで動作を確認したYesodチュートリアルサンプルをheroku上にデプロイしようとしてみましたが…エラーになりました。orz
    
    % git push heroku master
    Initializing repository, done.
    Counting objects: 95, done.
    Delta compression using up to 4 threads.
    Compressing objects: 100% (87/87), done.
    Writing objects: 100% (95/95), 78.89 KiB, done.
    Total 95 (delta 28), reused 0 (delta 0)
    
    -----> Fetching custom git buildpack... done
    -----> Haskell app detected
    -----> Downloading GHC
    ######################################################################## 100.0%
    -----> Downloading Cabal
    ######################################################################## 100.0%
    -----> Updating Cabal
    Downloading the latest package list from hackage.haskell.org
    Note: there is a new version of cabal-install available.
    To upgrade, run: cabal install cabal-install
    -----> Release the hounds! Installing application
    Resolving dependencies...
    cabal: Could not resolve dependencies:
    trying: Yosog-0.0.0
    trying: fast-logger-2.1.5
    rejecting: warp-2.0.2, 2.0.1, 2.0.0.1, 2.0.0 (conflict: Yosog => warp>=1.3 &&
    <1 .4="" conflict:="" rejecting:="" trying:="" wai-2.0.0="" warp-1.3.10.1="" warp=""> wai>=1.3 && <1 .5="" 2.0.0.1="" 2.0.0="" 2.0.1.1="" 2.0.1.2="" 2.0.1="" 2.0.2="" 2.0.3.1="" 2.0.3.2="" 2.0.3="" conflict:="" rejecting:="" trying:="" wai-1.4.1="" wai-extra-2.0.3.3="" yosog=""> wai-extra>=1.3 && <1 .4="" 1.3.2.4="" 1.3.3.1="" 1.3.3.2="" 1.3.3="" 1.3.4.1="" 1.3.4.2="" 1.3.4.3="" 1.3.4.4="" 1.3.4.5="" 1.3.4="" conflict:="" fast-logger="=2.1.5," rejecting:="" wai-extra-1.3.4.6="" wai-extra=""> fast-logger>=0.2 && <0 .4="" 1.3.0.1="" 1.3.0.2="" 1.3.0.3="" 1.3.0.4="" 1.3.0.5="" 1.3.0="" 1.3.1.1="" 1.3.1="" 1.3.2.1="" 1.3.2.2="" 1.3.2="" conflict:="" rejecting:="" wai-extra-1.3.2.3="" wai-extra="" wai="=1.4.1,"> wai>=1.3 && <1 .4="" 0.0.0.1="" 0.0.0.2="" 0.0.0="" 0.1.0="" 0.1.1="" 0.1.2.1="" 0.1.2="" 0.1.3.1="" 0.1.3="" 0.2.0="" 0.2.1="" 0.2.2.1="" 0.2.2.2="" 0.2.2="" 0.2.3="" 0.2.4.1="" 0.2.4.2="" 0.2.4="" 0.3.0="" 0.3.1="" 0.3.2.1="" 0.3.2="" 0.3.3="" 0.4.0.1="" 0.4.0.2="" 0.4.0.3="" 0.4.0="" 0.4.1.1="" 0.4.1.2="" 0.4.2="" 0.4.3="" 0.4.4="" 0.4.5.1="" 0.4.5.2="" 0.4.5="" 0.4.6="" 1.0.0.1="" 1.0.0="" 1.1.0.1="" 1.1.0="" 1.2.0.1="" 1.2.0.2="" 1.2.0.3="" 1.2.0.4="" 1.2.0.5="" 1.2.0="" conflict:="" rejecting:="" wai-extra-1.2.0.6="" yosog=""> wai-extra>=1.3 && <1 -="" .4="" app="" compile="" failed="" git="" haskell="" heroku.com:fierce-shore-6905.git="" master="" push="" rejected="" remote="" to=""> master (pre-receive hook declined)
    error: failed to push some refs to 'git@heroku.com:fierce-shore-6905.git'
    
    

    (3/2追記)
    上記のエラーは、ローカルでyesod init後にcabal installした際に、自分の環境の古い各種パッケージへの依存がYosog.cabalに記録され、Herokuで利用するビルドパック環境とあわないのが原因のようです。ローカルの環境をcabal updateで最新にして、cabal installした際に生成したYosog.cabalをコミットしてサーバーにデプロイしたところコンパイルは通るようになりました。
    ですが残念なことに、heroku openしてもサーバーにはつながらず…。原因調査中です。