scalaでコマンド叩くときのエラー
参考資料
- 公式ドキュメント
- http://kmizu.hatenablog.com/entry/20110510/1304985703
- http://www.mwsoft.jp/programming/scala/scala_process.html
エラー制御
エラーが2パターンある。
1、 コマンド自体実行できないと例外(IOException)が飛ぶ
scala> Process("foo").! java.io.IOException: Cannot run program "foo": error=2, No such file or directory at java.lang.ProcessBuilder.start(ProcessBuilder.java:1041) at scala.sys.process.ProcessBuilderImpl$Simple.run(ProcessBuilderImpl.scala:69) at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.run(ProcessBuilderImpl.scala:98) at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.run(ProcessBuilderImpl.scala:97) ... 33 elided Caused by: java.io.IOException: error=2, No such file or directory at java.lang.UNIXProcess.forkAndExec(Native Method) at java.lang.UNIXProcess.<init>(UNIXProcess.java:135) at java.lang.ProcessImpl.start(ProcessImpl.java:130) at java.lang.ProcessBuilder.start(ProcessBuilder.java:1022) ... 36 more
2、 コマンド実行後の失敗は例外飛ばず、デフォルトだと標準エラー出力
scala> Process("ls /foo").! ls: /foo: No such file or directory res11: Int = 1
例外のほうはTryでなんかすればいいとして、
標準エラー出力をロギングしたいときは、ProcessLoggerを使う。
def plogger = ProcessLogger(identity, logger.error(_)) Process("ls /foo") ! plogger
すごいHaskell本のメモ
FunctorやらMonadまわりのメモ。
Functor
箱と比喩されている。リストやMaybeなど大体Functor。
fmapをもってる。(Scalaでいうmap)
fmap :: Functor f => (a -> b) -> f a -> f b
aをとりbを返す関数と、Functor値aをとる。aに関数を適用してFunctor値bを返す。
Prelude> fmap (+1) (Just 1) Just 2
しかしFunctorだと中の関数に何かしようとすると辛くなる。
Prelude> let a = fmap (+) (Just 1) Prelude> :t a a :: Maybe (Integer -> Integer) 部分適用(カリー)されてMaybeの中に関数が入っている Prelude> fmap (\f -> f 1) a Just 2
これを簡単にできるのが↓
Applicative
文脈と比喩されている。リストやMaybeもまたApplicative。
pureと<*>を持っている。
Prelude> import Control.Applicative
pureは、aを受け取りapplicative aを返すだけの関数。
Prelude Control.Applicative> :t pure pure :: Applicative f => a -> f a
<*>は
Prelude Control.Applicative> :t (<*>) (<*>) :: Applicative f => f (a -> b) -> f a -> f b Appricativeに入った関数を受け取るところがFunctorと違う。 Prelude Control.Applicative> Just (+1) <*> Just 1 Just 2
functorで辛かった部分をapplicativeで書くと、
Prelude Control.Applicative> fmap (+) (Just 1) <*> Just 1 Just 2 短く書くこともできる↓ Prelude Control.Applicative> (+) <$> (Just 1) <*> Just 1 Just 2
簡単に書けた。
関数のApplicative
関数の<*>は、
f <*> g = \x -> f x (g x)
: fとgの関数を受け取り、g xした結果とxをfに渡す関数を返す
Prelude Control.Applicative> (+) <$> (+1) <*> (+1) $ 1 4
??
(+) <$> (+1) = (1 + a) + b (+) <$> (+1) <*> (+1) = \x -> (1 + x) + (1 + x) これに1を渡すと、4
たしかに4だ。
リストのApplicative
Prelude Control.Applicative> (+) <$> [1,2,3] <*> [2,3,4] [3,4,5,4,5,6,5,6,7]
それぞれに適用される。
ペアで適用したいときは、
Prelude Control.Applicative> getZipList $ (+) <$> ZipList [1,2,3] <*> ZipList [2,3,4] [3,5,7]
liftA2
Prelude Control.Applicative> :t liftA2 liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
aとbをとりcを返す関数と、Applicative値aとApplicative値bをとり、Applicative値cを返す関数。
Prelude Control.Applicative> liftA2 (+) (Just 1) (Just 2) Just 3
↓より↑のほうが分かりやすい。
Prelude Control.Applicative> (+) <$> (Just 1) <*> (Just 2) Just 3
Monoid
Monadとは別物。
ok : 1 + (2 + 3) == (1 + 2) + 3 (++や*など) ng : 1 - (2 - 3) == (1 - 2) - 3 みたいに順番変わってもokなもの
リストなら[]。(+)なら0。など
例
Prelude> import Data.Monoid Prelude Data.Monoid> [1,2] `mappend` [3,4] [1,2,3,4] Prelude Data.Monoid> "ab" `mappend` "cd" "abcd"
その他いろいろ
-- Sum, Product Prelude Data.Monoid> (Sum 1) `mappend` (Sum 2) Sum {getSum = 3} Prelude Data.Monoid> (Product 2) `mappend` (Product 2) Product {getProduct = 4} Prelude Data.Monoid> getProduct $ (Product 2) `mappend` (Product 2) 4 -- Any, All Prelude Data.Monoid> (Any True) `mappend` (Any False) Any {getAny = True} Prelude Data.Monoid> (All True) `mappend` (All False) All {getAll = False} -- compareは左側がEQのときに右側を評価 Prelude Data.Monoid> LT `mappend` GT LT Prelude Data.Monoid> EQ `mappend` GT GT
Foldable
畳み込むアレ
型
Prelude Data.Monoid> import Data.Foldable as F Prelude Data.Monoid F> :t F.foldl F.foldl :: Foldable t => (a -> b -> a) -> a -> t b -> a
例
Prelude Data.Monoid F> F.foldl (+) 0 [1,2,3] 6 Prelude Data.Monoid F> F.foldl (+) 1 (Just 1) 2
Monad
噂のアレ
Applicativeのupgrade版
型
-- pureと同じようにreturnがある Prelude> :t return return :: Monad m => a -> m a -- バインドと呼ばれる。scalaでいうflatMap。 Prelude> :t (>>=) (>>=) :: Monad m => m a -> (a -> m b) -> m b
例
Prelude> Just 1 >>= \x -> Just (x + 1) Just 2 Prelude> [1,2,3] >>= \x -> [x + 1] [2,3,4] Prelude> [1,2,3] >>= \x -> if x > 1 then [x] else [] [2,3] Prelude> Just 1 >>= \x -> Just (x+x) >>= \x -> Just (x*x) >>= \x -> if x > 10 then Just x else Nothing Nothing -- Scalaだと scala> Some(1) flatMap { x => Some(x+x) } flatMap { x => Some(x*x) } flatMap { x => if (x > 10) Some(x) else None } res6: Option[Int] = None
『あーScalaのアレと同じか』というのがちょいちょいあって助かる。
rubyでサムネイル作成
画像を指定のサイズでうまいことリサイズし、余白を埋め、透かしをいれる。
require 'RMagick' file = ARGV[0] def main(file, w, h) img = Magick::Image.read(file).first filename = img.filename img = watermark resize img, w, h img.write "dest/#{filename}" end def resize(img, w, h) img = img.resize_to_fit!(w, h) bg = Magick::Image.new(w, h) do self.background_color = 'white' end bg.composite!(img, Magick::CenterGravity, Magick::OverCompositeOp) end def watermark(img) mark = Magick::Image.read('./watermark.png').first img.composite!(mark, Magick::SouthWestGravity, Magick::OverCompositeOp) end main file, 100, 100
TypeScriptでScalaのOptionを
書いてみた。
使い方↓
Optional(x).map(i => i + 100).getOrElse(0) Optional(x).exists(i => i % 2 == 0)
(Optionは予約されてて使えなかったのでOptionalに)
もうほとんどScalaじゃ...!
TryとかEitherならすぐ書けそうだけどリスト周り書き出すとしんどそう...
TypeScript結構いいっぽい。coffeeも試してみたいけど型が...
class OptionT<A> { isEmpty: boolean get: () => A map<B>(f: (a: A) => B): OptionT<B> { return this.isEmpty ? new None : new Some(f(this.get())) } flatMap<B>(f: (a: A) => OptionT<B>): OptionT<B> { return this.isEmpty ? new None : f(this.get()) } getOrElse<B extends A>(d: B): A { return this.isEmpty ? d : this.get() } filter(f: (a: A) => boolean): OptionT<A> { return (this.isEmpty || f(this.get())) ? this : new None } exists(f: (a: A) => boolean): boolean { return !this.isEmpty && f(this.get()) } } class Some<A> extends OptionT<A> { isEmpty = false get = () => { return this.value } constructor(private value: A) { super() } } class None extends OptionT<any> { isEmpty = true get: () => any = () => { throw ""; "" } } var Optional = <A>(value: A) => { return value ? new Some<A>(value) : new None }
メソッド全然たりてないけど...まぁ。Noneが残念な感じになってる...
てきとうにテスト
var a = Optional(1).map(v => v + 100) console.log(a) // Some(101) var b = Optional(0).map(v => v + 100) console.log(b) // None var c = Optional(1).flatMap(v => Optional(v)).map(v => v + 1) console.log(c) // Some(2) var d = Optional(1).filter(i => i % 2 == 0).getOrElse(0) console.log(d) // 0 var e = Optional(1).exists(i => i % 2 == 0) console.log(e) // false
JavaScriptでもモナドを!
require.jsの、requireとdefineの違い
require.jsのことがよく分かってなかったので、コード読んで調べてみた。
require と define
- requireは、名前の通り実行すると、ファイルを読み込む。
- defineは、名前の通り定義をすると、キューに突っ込まれるだけで読み込みはしない。
requireを実行すると、<scirpt>
でファイルを読み込む。
読み込んだファイル内にはdefine([‘foo/bar’], function() { .. })
とか書いてるのでdefineされてるものはキューに突っ込まれる。
require完了後setTimeout(4ms)したらキューを処理するので、defineしたものも読み込まれる。
読み込んだものは、グローバルなオブジェクトで管理されて同じものは読み込まれないようになっている。
例
foo.js
define([‘bar1’, 'fuga2'], function() { … })
bar1.js
define([‘piyo3’], function() { … })
があるとして、
require(“foo”)
を実行する。
fooが読み込まれ、defineのものがキューに入る。[bar1, fuga2]
キューが処理される。最初はbar1。bar1にはpiyo3がdefineされているので、またキューに入る。[fuga2, piyo3]
キューがなくなるまで読み込み続ける。
幅優先探索のようになっている。
git cherry-pickで複数まとめて取り込む
masterに緊急でコミットしてしまって、後で開発ブランチと整合性合わせたいみたいな状況(仮)
差分を確認します。
$ git cherry -v develop master 84a9532902724a2c26c746aae2505bc60e66e7cb 緊急対応。index.html修正 9e630b327fa7879562bff8b3772f36e6a0e74ca9 緊急対応2。typo.. eb8fa59260d7f304836a790a298008fedf00f2d3 緊急3。リンク切れ対応
取り込みます。
$ for cid in $(git cherry -v develop master | awk '{print $2}'); git cherry-pick $cid [develop 0861381] 緊急対応。index.html修正 1 file changed, 1 insertion(+), 1 deletion(-) [develop 967988d] 緊急対応2。typo.. 1 file changed, 1 insertion(+), 1 deletion(-) [develop 8aee8b7] 緊急3。リンク切れ対応 1 file changed, 1 insertion(+), 1 deletion(-)
何がいいたいかと言うと、cherry-pickでうまくまとめて取り込めなかったので、頑張らずにforでいいじゃないかと。
CoffeScriptをさらに書きやすくしたLiveScript
LiveScriptは、CoffeScriptをもっとよくしたCocoのfork。
LiveScriptで書かれたpreludelsというライブラリがあるので関数型っぽい関数が使える。(foldやらscanやら)
Function
カリー化
f = (x, y) --> x * y f(2)(2) # 4 f = (x) -> (y) -> x * y f(2)(2) # 4
合成
f = (x) -> x + 1 g = (y) -> y + 2 (f << g)(1) # 4 (f . g)(1) # 4 (f >> g)(1) # 4
List
パイプ
[1 to 10] |> map (i) -> i * i |> reverse |> head # 100
リスト内包
[ x + y for x to 3 when x % 2 is 0 for y to 3 ] # [0,1,2,3,2,3,4,5]
etc..
zip [1 to 3] [\A to \C] # [[1,"A"],[2,"B"],[3,"C"]] scan (+), 0, [1 to 3] # [0,1,3,6] fold (+), 0, [1 to 5] # 15 take-while odd, [1 3 5 6] # [1 3 5]
定義
obj = * name: 'tessa' age: 23 # {"name":"tessa","age":23} <[ a b c ]> # ["a", "b", "c"]
未実装
f = -> ... f() # throw Error('unimplemented');
パターンマッチ
f = -> switch it | 0 false null undefined => "ng" | "foo" => "bar" | _ => "ok" f(0) # ng f(1) # ok
正規表現
/^[a-z]*/ == "abc123" # [abc]
再帰
sum
sum = (list, acum = 0) -> | !list.length => acum | _ => [head, ...tail] = list sum(tail, acum + head) sum([1,2,3]) # 6
qsort
qsort = (list) -> | !list => [] | list.length is 1 => [head list] | _ => h = head list {l, c, r} = group-by ((i) -> | h > i => "l" | h == i => "c" | h < i => "r"), list qsort(l) ++ c ++ qsort(r) qsort([3,1,2,4,5,-1,-1,2]) # [-1,-1,1,2,2,3,4,5]
だいぶ短く書けるようだ。
しかしheadとtailが書きづらい。
まとめ
これがJSだと思うとだいぶいいと思う。
coffescriptよりもさらに短く書けて、cocoのforkなのでより最適化されている。というかパターンマッチが書きやすい!
関数型やってる人にはいいかもしれない。(・・`)