purescript-conveyorにLogger実装足しといた

追記

本記事のパッケージは現在メンテされておりません。

サーバー向けパッケージは再実装されたものがこちらにあります。

Bucketchain


足した

あくまでデフォルト実装としての簡易的なLoggerです。

基本的にはこの実装を参考にして、みなさんのお好きなLoggerをつくってServableにしてくださいということでひとつ。

椅子を高級品にした

いきさつ

ある日、自宅作業中に背もたれによっかかったら、小さく「ミシッミシミシミシ」と音を立てていたのだが、その瞬間はあまり気にしていなかった。 そのまましばらくよっかかっていると、どうも少しずつ背もたれが倒れていっているようなので、これはおかしいと思い、椅子をよく見てみると、 背もたれの留め具の部分が完全に破損して飛び出ていた。床をみると破片がめっちゃ落ちていた。 サンワサプライのやっすい椅子を使っていたのだが、私は体格がいいほう(178cm 90kg弱)なので私の体重に耐えきることができなかったっぽい。 たぶん2年くらいしかつかっていない。

そういうわけで、私もフリーランスになったため、そろそろ良い椅子を買おう、ということにしました。

何買うか

実は以前の職場でコンテッサを使っていて結構よかった記憶があるのでコンテッサが第一候補ではあったが、せっかくなので調査と視座をすることにした。

事前調査としては、椅子の基本方針として、「前傾」をサポートするか「後傾」をサポートするかというのがあり、そこがわりと大きな違いにはなりそうな感じであった。 また、ハーマンミラー製品は他のメーカーと比べて大きな違いがあり、他のメーカーよりも保証の条件が厳しい代わりに、保証期間が12年でとても長いということもこのタイミングで知った。

試座

試座は自分の普段のデスクワーク時の姿勢の変化やスタイルを意識してやると良いという事でそういう感じでやった。

近場を何店舗か回りながら視座してみたが、私はちょっと困っていた。 というのも、ぶっちゃけ数分程度の試座だと、高級なオフィスチェアは、どれもとても座り心地がよく、どれがいいという感じにならなかったのである。これは以前の職場で椅子を選ぶときに全く同じ感想があったのを思い出した。

私は作業中かなり前傾姿勢になるので前傾チルトは絶対にほしいのでそれがついていることと、保証が12年ということでハーマンミラーの製品にするかーという感じで決めた。

結局何買ったのか

相当悩んだが、結局セラチェアを買った。 セラチェア - オフィスチェア - ハーマンミラー

f:id:oreshinya:20180204162912j:plain

実は、今回椅子を買うときにひどいギャンブルをしてしまっていて、ハーマンミラー製品のうち、このセラチェアだけは全く座ったことがない。 この椅子は置いてあるところが少ないのだ。

なぜ、そんな頭の悪いことをしてしまったかというと、高けりゃだいたいある程度満足感があることは試座でわかっていたのもあるが、 とてもほしくなってしまったからなのだ...。

買う前に何がそんなに気に入ったかというと、

  • 布を使っていないので汚れにつよく、ヘタリに対しても特にかなり強そうだったこと
    • できることならノーメンテで長く使いたいから
  • メッシュすらないとか、唯一無二感あって、めっちゃかっこいいなこれって感じだったこと
    • 私はこういう感じの製品をめっちゃかっこいいと思ってしまうタイプ

こんな感じでビビッときてしまった。

ほんで、地味に調整機能は高機能で必要な調整機能は全て揃っていたこと、体格のいい人間にはかなりマッチする(らしい)というインターネットの情報から、「まぁ座ってないけど買っちゃお!えい!!!!!!!」って感じで買っちゃった感じです。

ただし、調査では、「座面が硬く感じる、冷たく感じる」という意見もあり、正直到着するまでビクビクしていた。

届いてから

到着時はとてもでかいダンボールに入って届けられるので、家に入らず、廊下で開封作業を行った。

んで、実際使ってみての感想だが、丸1日座っているがかなり最高で、座面の件も硬くないし、(たぶん暖房つけてるからだけど)冷たくもない。 クッションもないのに、不思議とケツも痛くならない。私はこの椅子にマッチするタイプだったらしい。これはセラチェア独自のセルラーサスペンションとかいう仕組みによるものっぽい。

ギャンブルに勝った。買ってよかった。

PureScriptで静的ファイル配信できるパッケージ書いた

追記

本記事のパッケージは現在メンテされておりません。

サーバー向けパッケージは再実装されたものがこちらにあります。

Bucketchain

はじめに

静的ファイルを配信するときはとりあえずnginxなどにお任せすればいいかと思いつつも、 昨今ではTwelve-Factor Appの考え方もあり、静的ファイルの配信もアプリケーションサーバーでしようということで、 PureScriptで静的ファイル配信するパッケージを書きました。

本番ではCDNのオリジンとして動いてもらうという感じにはなると思います。

どんなやつ?

リポジトリGitHub - oreshinya/purescript-static-serve: Serve static filesです。

ランタイムはnodejs想定です。

とりあえず最低限ということで、雑に言うと以下の3つのみ対応しています。

  • 静的ファイル配信
  • maxageの設定
  • 条件付きGETの対象については、Last-Modifiedのみ対応しておりETagは対応していません。

使い方

module Main where

import Prelude

import Control.Monad.Eff (Eff)
import Data.JSDate (LOCALE)
import Data.Maybe (Maybe(..))
import Node.FS (FS)
import Node.HTTP (HTTP, ListenOptions, createServer, listen)
import StaticServe (staticHandler)



config :: ListenOptions
config =
  { hostname: "0.0.0.0"
  , port: 3000
  , backlog: Nothing
  }



main :: forall e. Eff (fs :: FS, http :: HTTP, locale :: LOCALE | e) Unit
main = do
  server <- createServer $ staticHandler { root: "./public", maxAge: 60 }
  listen server config $ pure unit

現段階では、設定としては、rootディレクトリの設定とmaxageの設定のみです。

この例だとpublic以下に置いたファイルが配信されるようになります。

さいごに

やったぁPureScriptで静的ファイル配信できるようになったぁ(小並感)

(このパッケージがエッジケースに対応できているかは微妙な感じです。)

追記

昨日作ったこのパッケージにHistory API Fallback機能つけました。これでSPAもオッケーです。

最近仮想通貨買いはじめた

年末に初めて仮想通貨を購入した。 アーリーアダプターではないが、夢のある感じで楽しい。

チャート漁り、情報漁り、草コイン漁りがめっちゃ楽しい。

明らかにバブルという感じで、我々の上の世代はこんな楽しいことを経験していたのかという感覚がある。

通貨を購入した瞬間に金を捨てたと自己暗示しまくって買っていると、短期的な値下がりが気にならないタイプなので楽しめているのかもしれない。

今年は余剰資金が増える予定なので、いろいろ買っていきたい。

PureScriptの末尾再帰最適化

はじめに

年が明けてますが、PureScript Advent Calendar 2017 - Qiitaの19日目の記事にしてしまいます。

PureScriptは末尾再帰最適化ありますが、モナディックな再帰は最適化されません。 よって、何も考えないと稀に、コールスタックに積み上がりすぎてエラーが起こるという状況に遭遇するかもしれません。 というか私は遭遇しました。 そんなときのためのパッケージを紹介します。

紹介

後者はtailrecをラップしたパッケージです。

これらを使って書き直すと、きっとエラーが起こらなくなるはずです。

さいごに

サンプルコード書こうかと思ったけど、まぁREADME読めばわかるしええやろ、という気持ちで手抜きの記事となりました。

purescript-conveyorにBatch operationの機能を足した

追記

本記事のパッケージは現在メンテされておりません。

サーバー向けパッケージは再実装されたものがこちらにあります。

Bucketchain

はじめに

年が明けてますが、PureScript Advent Calendar 2017 - Qiitaの21日目の記事にしてしまいます。

前回、PureScriptでAPIサーバー用のパッケージつくってみた - oreshinyaのブログというようなAPIフレームワークをつくったことを記事にしましたが、 このフレームワークにBatch opearationの機能を足しました。 また、その際に全面的にソースコードを書き直したため、変更点を書きます。

Batch operationってなに

複数のエンドポイントを1回のリクエストで実行する機能です。

複雑なアプリケーションになると、ひとつの画面に必要なデータが非常に多岐に渡ります。 そのような状況下の中、ひとつのAPIで色々な多くのデータを返すか、単機能なAPIを複数回叩くかという選択をすることを最初に考えるかと思います。 このことに対して、何も対策的な仕組みを入れない場合、前者の場合はUIによりすぎたメンテのしにくいAPIによっていくし、後者は何度もリクエスト往復するのでとても時間がかかります。

こういったことに対して、数年前からBFFという概念が公に出るようになりました。 ただ、気合の入ったBFFをしなくても、単純なbatch operationだけでもあると、経験上、わりと快適になるため、自分で使うためのライトユースとして、この機能を足しました。

Servableのメンバの型が変わった

変更コミットたちです。

Batch operationを入れるために、Servableのメンバの型を変えました。 以前の型はserve :: c -> s -> Request -> Response -> String -> Maybe (Eff (http :: HTTP | e) Unit)で、新しい型はserve :: s -> c -> RawData -> Aff e Responderになります。

大きな変更点は、返り値の型となります。

以前の型では、serveの実行文脈の中でレスポンスをクライアントに返すことを期待した型付けでしたが、新しい型では、serveの文脈でレスポンスとなるデータをつくって返すだけになっています。

新しい型にしたことによって、batch operationの実装は、serveを指定された各エンドポイントのパラメータの配列を用いて、traverseして複数のレスポンスをまとめればいいだけになりました。

その他の変更

  • Request bodyのdecodeに関しては、purescript-simple-jsonに依存するように変更して、Readable型クラスを削除した
  • Respondable型クラスの全面的な書き直し
  • Handlerを削除して、普通にAffで動くように変更した
  • 関数の引数の順番とか数とか引数そのものを地味に変えた
  • まぁ、なんか色々書き直した

まだ改善できるところはある

現状は、各エンドポイントを順番に処理してるだけなので、concurrentに実行できるようにするとよりよさそうです。

使い方

ServableインスタンスBatch型で包んで初期化すれば、OKです。 リポジトリのサンプルコードとほぼコピペですが、以下のような感じで初期化します。

runWithContext config 777 $ Batch { contextTest, errorTest, rawDataTest, createBlog }

以下のようなデータをrequestのbodyとして、POST /batchにおくりつけると、

[
  {"path": "errorTest"},
  {"path": "contextTest"},
  {"path": "createBlog", "body": { "title": "hoge", "content": "うんち in batch" }},
  {"path": "rawDataTest", "body": "ろーでーた"}
]

以下のようにかえってきます。

[
    {
        "contentType": "application/json",
        "code": 500,
        "body": {
            "messages": [
                "Internal server error ;)"
            ]
        }
    },
    {
        "contentType": "application/json",
        "code": 200,
        "body": {
            "yours": "777"
        }
    },
    {
        "contentType": "application/json",
        "code": 200,
        "body": {
            "fuck": "title: hoge, content: うんち in batch requested."
        }
    },
    {
        "contentType": "application/json",
        "code": 200,
        "body": {
            "yours": "\"ろーでーた\""
        }
    }
]

単純パーセプトロンを実装してみた

年が明けていますが、PureScript Advent Calendar 2017 - Qiitaの20日目の記事にしてしまいます。

Python機械学習プログラミングを2章まで読んだ。

読んだ内容を体にいれるために、適当にPureScriptで単純パーセプトロンを実装してみる。

module Main where

import Prelude

import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, log)
import Control.Monad.State (StateT, execStateT, get, modify, put)
import Control.Safely (replicateM_)
import Data.Array (snoc, zipWith)
import Data.Foldable (sum)
import Data.Traversable (for)
import Data.Tuple (Tuple(..))


-- 学習によって更新されていく値
type State =
  { weights :: Array Number
  , bias :: Number
  , errors :: Array Number
  }



main :: forall e. Eff (console :: CONSOLE | e) Unit
main = do
  -- 学習率は0.01とし、エポック数は10としてみる
  state <- flip execStateT initialState $ fit 0.01 10
  log $ "expected: 1.0, gotten: " <> (show $ predict $ netInput [1.0, 1.0] state)
  log $ "expected: -1.0, gotten: " <> (show $ predict $ netInput [0.0, 1.0] state)
  log $ "expected: -1.0, gotten: " <> (show $ predict $ netInput [1.0, 0.0] state)
  log $ "expected: -1.0, gotten: " <> (show $ predict $ netInput [0.0, 0.0] state)
  log $ "weights: " <> show state.weights
  log $ "bias: " <> show state.bias
  log $ "errors: " <> show state.errors


-- 学習
fit :: forall e. Number -> Int -> StateT State (Eff e) Unit
fit eta iter =
  replicateM_ iter do
    errors <- for samples \(Tuple xs y) -> do
      st <- get
      let d = eta * (y - predict (netInput xs st))
      put $ st
        { weights = zipWith (+) st.weights $ map ((*) d) xs
        , bias = st.bias + d
        }
      pure d
    -- イテレーションごとに雑に誤差をいれておく
    modify \s -> s { errors = snoc s.errors $ sum errors }


-- ステップ関数
predict :: Number -> Number
predict z =
  if z >= 0.0
    then 1.0
    else -1.0


-- 総入力
netInput :: Array Number -> State -> Number
netInput xs { weights, bias } =
  bias + (sum $ zipWith (*) xs weights)


-- 初期状態
initialState :: State
initialState =
  { weights: [ 0.0, 0.0 ]
  , bias: 0.0
  , errors: []
  }


-- サンプル
-- 特徴量と期待する出力
samples :: Array (Tuple (Array Number) Number)
samples =
  [ Tuple [ 0.0, 0.0 ] (-1.0)
  , Tuple [ 0.0, 1.0 ] (-1.0)
  , Tuple [ 1.0, 0.0 ] (-1.0)
  , Tuple [ 1.0, 1.0 ] 1.0
  ]

今回はAND演算を学習させてみた。

実行してみる。

expected: 1.0, gotten: 1.0
expected: -1.0, gotten: -1.0
expected: -1.0, gotten: -1.0
expected: -1.0, gotten: -1.0
weights: [0.04,0.02]
bias: -0.06
errors: [0.0,-0.02,-0.02,0.0,-0.02,0.0,0.0,0.0,0.0,0.0]

6回目から誤差が出なくなっているっぽい。

ADALINEも実装しようと思ったが、飽きたので一旦終了。