ブロッコリーとカリフラワーを畑とベランダで育てている

タイミング逃しまくりで、先週やっとスナップエンドウとブロッコリー、カリフラワーを定植した。

カリフラワーは一度きりの収穫だが、ブロッコリーは定期的に畑詣でする必要があって面倒くさいので、ベランダでも育てることにした。

1356341496

敷き藁が余っていたのでプランターにも敷いてみた。

1356341498

virthualenvwrapperをつくった

この前mkvirthualenvを書いたんだけど、消したりリストできないと使いづらいのでvirthualenvwrapperという名前でGitHubにあげておいた。

git cloneしてcabal installすればmkvirthualenv,rmvirthualenv,lsvirthualenvの3つのコマンドが使えるようになるはずですが、cabalで設定するの初めてなのでおかしかったら指摘してください。

仮想環境をつくる

mkvirthualenv yesod

で仮想環境が作られるのでworkhonで入る

$ workhon yesod
Activating yesod Virtual Haskell Environment (at /Users/kzfm/.virthualenv/yesod).

Use regular Haskell tools (ghc, ghci, ghc-pkg, cabal) to manage your Haskell environment.

To exit from this virtual environment, enter command 'deactivate'.
(yesod)localhost@kzfm:~ $

好きなライブラリを入れまくる。そもそもpersistentがおかしくて、仮想環境を作っては消しを繰り返していたのが、ラッパー構築の動機

cabal install yesod-platform-1.1.5
cabal install persistent-sqlite-1.0.1

仮想環境一覧表示

lsvirthualenvコマンドを使う

$ lsvirthualenv 
diagrams
hakyll
per2
persistent
scotty
snap
yesod

ちょっとyesodが嫌になってsnapに浮気しかけた時期(今朝とか)がありました。

仮想環境を削除する

rmvirthualenvコマンド

$ rmvithualenv snap
$ lsvirthualenv 
diagrams
hakyll
per2
persistent
scotty
yesod

個人的にはフルスタックのフレームワークよりも、Flaskのように好きに組み合わせて作っていくのが好きなのでsnapに惹かれたんだけど、Modelのsnapletがコアについていってない感じがした。

HDBCもエラーになるし、sqlite-simpleもORマッパーぽくなくてなんかいまいちだった。あとドキュメントが少ないので困ったので、yesodで行こうと思った。

ProductName Developing Web Applications With Haskell and Yesod
Michael Snoyman
Oreilly & Associates Inc / 2805円 ( 2012-05-04 )


本棚オーバーフロー

本棚があふれてどうしようもないので少し処分することにした。ブックオフに持っていけそうなものはそっちに出すとして、技術書や洋書は面倒くさいので次のゴミの日に捨てる予定。

知り合いのなかで、もし欲しいのがあったら教えてください。今度会う時に持っていきます。

1356235738

1356235740

1356235741

写真に撮り忘れたけど、ふつうのHaskellと入門Haskellも不要なので欲しい人がいれば僕まで連絡お願いします。

ProductName ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門
青木 峰郎
ソフトバンククリエイティブ / ?円 ( 2006-06-01 )


ProductName 入門Haskell―はじめて学ぶ関数型言語
向井 淳
毎日コミュニケーションズ / ?円 ( 2006-03 )


ScottyはHaskellのSinatraクローン

ScottyはHaskell版のSinatraですね。

普段はFlask使ってるし、NodeでWebアプリ使う時にはExpressを使うので、これ以上Sinatraクローンを覚えたいとは思わないが、ソースコードを読んで勉強するにはちょうどいいサイズだった。

newtype ActionM a = AM { runAM :: ErrorT ActionError (ReaderT ActionEnv (StateT Response IO)) a }
    deriving ( Monad, MonadIO, Functor
             , MonadReader ActionEnv, MonadState Response, MonadError ActionError)

モナド変換子の重ね方が参考になった。Scottyの場合はErroTでリダイレクトとかの処理をするようになっている。

defaultHandler :: ActionError -> ActionM ()
defaultHandler (Redirect url) = do
    status status302
    header "Location" url
defaultHandler (ActionError msg) = do
    status status500
    html $ mconcat ["<h1>500 Internal Server Error</h1>", msg]
defaultHandler Next = next

参考

括弧が省略できてインデントでネストが表現できる言語だとコードの見通しが良くていいですね。

{-# LANGUAGE OverloadedStrings #-}
import Web.Scotty
import Data.Monoid

main :: IO ()
main = scotty 3000 $ do
    get "/" $ text "Helllo Scotty"

    get "/lang" $ do
        v <- param "type"
        html $ mconcat ["<h1>", v, "</h1>"]

カタカナのしりとりの圏

モナモナ言うモナド入門を読んでプチ圏論ブームがやってきたっぽいので、改めてはじめての圏論 その第1歩:しりとりの圏を読んでみた。

読んだ当時は、射の集合がひらがなの文字列っていうのがいまいちイメージがわかなかったのだけど、改めて読んでみるとdomとcodを決めるルールなんだから文字列でいいのかと納得した。

さて、カタカナの文字の集合を考えてしりとりの圏を作ったとする。この場合、ひらがなの圏をカタカナの圏に関連付けるものはfunctorなのだろう。

アルファベットのしりとりの圏を作ってそれをひらがなの圏と対応付けるのもまたfunctorなのだろうか(一対一で対応しないけど)?と思ったが、これの圏論の説明をみるかぎりそんな気がする。

ProductName Basic Category Theory for Computer Scientists (Foundations of Computing)
Benjamin C. Pierce
The MIT Press / 2302円 ( 1991-08-07 )


PersistentのMigrationが便利そうだ

Persistentを触ってみている

{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-}
{-# LANGUAGE GADTs, FlexibleContexts #-}
import Database.Persist
import Database.Persist.Sqlite
import Database.Persist.TH
import Control.Monad.IO.Class (liftIO)

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persist|
Person
    name String
    age Int Maybe
    loc String default="Japan"
    deriving Show
|]

main :: IO ()
main = withSqliteConn "test.db" $ runSqlConn $ do
    runMigration migrateAll
    johnId <- insert $ Person "kzfm" (Just 20) "Fuji"
    liftIO $ print johnId

実行するとデータベースが作られる。実行されるSQLはごく普通のcreate文

CREATE TABLE "Person"("id" INTEGER PRIMARY KEY,"name" VARCHAR NOT NULL,"age" INTEGER NULL)

続いてEntityを変更してみる。locを追加してdefaultも付けておく。ついでにinsertのとこも修正しておく

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persist|
Person
    name String
    age Int Maybe
    loc String default="Japan"
    deriving Show
|]

main :: IO ()
main = withSqliteConn "test.db" $ runSqlConn $ do
    runMigration migrateAll
    johnId <- insert $ Person "kzfm" (Just 20) "Fuji"
    liftIO $ print johnId

バックアップテーブルにデータが移され、もとのテーブルが変更された後、データが戻されて移行が無事に完了する。

CREATE TEMP TABLE "Person_backup"("id" INTEGER PRIMARY KEY,"name" VARCHAR NOT NULL,"age" INTEGER NULL,"loc" VARCHAR NOT NULL DEFAULT "Japan")
INSERT INTO "Person_backup"("id","name","age") SELECT "id","name","age" FROM "Person"
DROP TABLE "Person"
CREATE TABLE "Person"("id" INTEGER PRIMARY KEY,"name" VARCHAR NOT NULL,"age" INTEGER NULL,"loc" VARCHAR NOT NULL DEFAULT "Japan")
INSERT INTO "Person" SELECT "id","name","age","loc" FROM "Person_backup"
DROP TABLE "Person_backup"

Entityのデフォルトはデータ移行時のもとのカラムに付加される値であって、insertで省略できるわけではないので、insertは明示的に値を入れないといけない。databaseを見てみるともとのデータのlocにはEntityのデフォルトで指定したJapanという値が入っていることがわかる。

sqlite> select * from person;
1|kzfm|20|Japan
2|kzfm|20|Fuji

ちなみにEntityのデフォルトを指定しないとマイグレーションに失敗するが、Maybe型にしておけばnullが入るので移行できる。

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persist|
Person
    name String
    age Int Maybe
    loc String Maybe
    deriving Show
|]

開発している時にスキーマの変更はそれなりに苦痛を伴う作業なので、ある程度面倒見てくれるのはありがたい。ダメなときはダメって言ってくれるし。

Persistentのマイグレーションは保守的なので安心らしい。次のケースで自動的にスキーマの変更がなされる。

  • フィールドのデータタイプが変更された時 。ただし変更できる時のみ
  • (The datatype of a field changed. However, the database may object to this modification if the data cannot be translated.)
  • フィールドが追加された時で、フィールドがnot nullの場合はdefaultが指定されている時
  • (A field was added. However, if the field is not null, no default value is supplied (we'll discuss defaults later) and there is already data in the database, the database will not allow this to happen.)
  • フィールドがnot nullからnullに変更された時。逆のケースも試みるがデータベース次第
  • (A field is converted from not null to null. In the opposite case, Persistent will attempt the conversion, contingent upon the database's approval.)
  • 新しいエンティティが追加された時
  • (A brand new entity is added.)

ProductName Developing Web Applications With Haskell and Yesod
Michael Snoyman
Oreilly & Associates Inc / 2805円 ( 2012-05-04 )


Haskellのpersistentが動かない

persistent-1.1.0.1,persistent-template-1.1.1が入っている。

Persistentのsynopsisの例を実行すると

No instance for (Control.Monad.Trans.Resource.MonadResource IO)
  arising from a use of `selectList'
Possible fix:
  add an instance declaration for
  (Control.Monad.Trans.Resource.MonadResource IO)
In a stmt of a 'do' block:
  oneJohnPost <- selectList [BlogPostAuthorId ==. johnId] [LimitTo 1]
In the second argument of `($)', namely
  `do { runMigration migrateAll;
        johnId <- insert $ Person "John Doe" $ Just 35;
        janeId <- insert $ Person "Jane Doe" Nothing;
        insert $ BlogPost "My fr1st p0st" johnId;
        .... }'
In the second argument of `($)', namely
  `runSqlConn
   $ do { runMigration migrateAll;
          johnId <- insert $ Person "John Doe" $ Just 35;
          janeId <- insert $ Person "Jane Doe" Nothing;
          insert $ BlogPost "My fr1st p0st" johnId;
          .... }'

困った。

ProductName Developing Web Applications With Haskell and Yesod
Michael Snoyman
Oreilly & Associates Inc / 2805円 ( 2012-05-04 )


追記 121220

これは動く

{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-}
{-# LANGUAGE GADTs, FlexibleContexts #-}
import Database.Persist
import Database.Persist.Sqlite
import Database.Persist.TH
import Control.Monad.IO.Class (liftIO)

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persist|
Person
    name String
    age Int Maybe
    deriving Show
|]

main :: IO ()
main = withSqliteConn "test.db" $ runSqlConn $ do
    runMigration migrateAll
    -- johnId <- insert $ Person "John Doe" $ Just 35
    -- liftIO $ print johnId

insertしたりselectListしたりするとNo instance for (Control.Monad.Trans.Resource.MonadResource IO)が出る。

追記 121220

これか? - Simplified Persistent Types

追記 121220

バージョンを下げたら動いたので当分この組み合わせで使う

  • persistent-1.0.2.2
  • persistent-sqlite-1.0.1
  • persistent-template-1.0.0.2

diagramsが素敵すぎる

diagramsを使ってみた。

{-# LANGUAGE NoMonomorphismRestriction #-}
import Diagrams.Prelude
import Diagrams.Backend.SVG.CmdLine
import Data.Colour

tri c n = dots <> (strokeT edges # lc c # lw 0.2 # fcA (c `withOpacity` 0.5))
  where rows = map (hcat' with { sep = 1 })
             . zipWith replicate [n,n-1..1]
             . repeat
             $ dot c
        dots = decorateTrail (rotateBy (1/6) edge) rows
        edge = fromOffsets . replicate (n-1) $ unitX # scale 3
        edges = close (edge <> rotateBy (1/3) edge <> rotateBy (2/3) edge)

dot c = unitCircle # lw 0 # fc c

rowSpc = height (rotateBy (1/6) $ strutY 1 :: D R2)
row k n s c = hcat' with {sep = 1 + 3*s} (replicate k (tri c n))
law4 k n c1 c2 = vcat' with {sep = rowSpc} (map tRow [1..k])
  where tRow k = (row k n 0 c1 # centerX # alignT)
                 <>
                 (row (k-1) (n-1) 1 c2 # reflectY # centerX # alignT)
exampleRow f = hcat' with {sep = 4} . map (alignB . f)

law4Dia = exampleRow law4' [2..4]
  where law4' k = law4 k 3 purple gold

example = pad 1.1 $ law4Dia # centerXY

main = defaultMain example

これだけで下のような図が作成できる

diagrams

PyJadeでenumerateしたりstrしたい

僕はJade派なのでPythonでもJadeを使うわけだが、jadeテンプレートのなかでゴニョゴニョしたい時にハックっぽいことをしないといけないのは何とかならんかなぁと思っている。

enumerate

配列のインデックス値が欲しい時

for elm in ary
  i = ary.index(elm)

とやっている。

str

Intを文字列にしたい時str関数が使えないので

elm.id.__str__()

とやっている。

pythonの組込み関数使えると嬉しいんだけど、やり方あるのかな?

山を歩こう

そろそろ歩きたいなぁと思って近場の山を探すために買ってみた。

ProductName 新・分県登山ガイド 改訂版21 静岡県の山
加田 勝利
山と渓谷社 / 1995円 ( 2009-12-16 )


浜石岳とか白水山でも登ってみようかな。

そういえば去年のGDDで山系のARアプリが出てたので、「かざすと登れるかどうか判定してくれると嬉しいなぁ」とか言ってみたんだけど、そういうのだったら本と同じ値段(2K)くらいは出してもいいかもと思った。

山渓にはアプリを頑張って欲しい。