2008年03月16日

PowerShellですごいテクニックを発見した!

最近はPowerShellを常に起動していて、コマンドプロンプトを使わずにPowerShellから色々作業するようにしている(Pythonなどの対話環境もPowerShellから起動している)のですが、そのようななかで個人的にこれはすごいと思えるテクニックを発見しました。

それはたったひとつのコマンド、

PS > powershell

です。「PowerShell内でPowerShellを起動する」。何が嬉しいかというと、スクリプトなりを実行してPowerShellが強制終了した場合に内側のPowerShellが強制終了するだけで外側のPowerShellは生き残るという点です。エラーメッセージも残せます。これで自分でもどうかなと思うような実験的なスクリプトの実行も怖くありません。これはすごい! 画期的!

あー、でもこれ、シェル使いの方には常識だったりするんでしょうか。そうだったら恥ずかしい……。

追記(2008年03月22日)

2chのスレッド「Windows PowerShell (正式版リリース)1.0」の592番目のレスにすでに同様のテクニックが書かれているというコメントをいただきました。けっこうすごい発見だと思ったのですが、やはりというかなんというか、先駆者がおられました。

ただ、こういったコメントをいただくということは「シェル内シェル」はあまり一般的ではないようにも見受けられますね。その点については安心しました。

posted by bakemoji at 23:54| Comment(3) | TrackBack(0) | PowerShell | このブログの読者になる | 更新情報をチェックする

2008年03月08日

OCamlのお勉強 その6 〜多相と型推論、コンビネータ〜

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~」を読んでの勉強記録です。

型推論によって型が確定されない引数を持つ関数は多相的関数となる。

# let add x y = x + y;;
val add : int -> int -> int = <fun>
# let k x y = x;;
val k : 'a -> 'b -> 'a = <fun>

関数addはint型の値x、yを受け取ってint型の値を返す関数となっているのに対し、関数kは何らかの型'a、'bの値x、yを受け取って'a型の値を返す関数となっています。addについてはx + yという式からx、yはint型だと推論できますが、kについてはx、yの具体的な型は決めようがありません。こういった関数を多相的関数というそうです。C#で近い機能というとジェネリクスですね。

この本では、ケーススタディとしてコンビネータに触れています(アカデミックですね!)。最近Yコンビネータで話題のあれです。先ほどの関数kは、基本となる2つのコンビネータのうちの1つで、Kコンビネータと呼びます。もうひとつはSコンビネータです。

# let s x y z = x z (y z);;
val s : ('a -> 'b -> 'c) -> ('a -> 'b) -> 'a -> 'c = <fun>

Kは定数関数を返す関数で、Sは置換演算子(なんでこう呼ぶのかはわかりません)です。Kについては、「定数関数を返す」ということをそのまま表現すると

# (* xを受け取り、どんな引数だろうと常にxを返す関数を返す *)
  let k x = fun y -> x;;
val k : 'a -> 'b -> 'a = <fun>

とも書けますね。SとKの組み合わせで様々な関数を構築できます。S、Kの組み合わせの単純な例としてIコンビネータがあります。

# s k k 19;;
- : int = 19
# s k k "hello";;
- : string = "hello"

Iコンビネータは与えられた引数をそのまま返す恒等関数です。なぜこのような動作するのでしょうか。擬似コードで関数適用の流れを追ってみます。

s x y = fun z -> x z (y z)        (* sの書き直し *)
s k k = fun z -> k z (k z)        (* x、yをkで置き換え *)
      = fun z -> k z (fun a -> z) 
      = fun z -> z                (* k x y = xより *)

確かにs k kは恒等関数となっています。コンビネータに関する練習問題も解いてみました。

恒等関数を、s k kで表現したように、関数fun x y -> yをコンビネータskを関数適用のみで(funletによる関数定義を使わずに)組み合わせた形で表現しなさい。

4.4 練習問題,p83
# k (s k k);;
- : '_a -> '_b -> '_b = <fun>
# k (s k k) 0 1;;
- : int = 1
# k (s k k) 0 "later";;
- : string = "later"

合っていそうです。先ほどのように関数適用の流れを追ってみます。

k (s k k) = k (fun y -> y)
          = fun x -> (fun y -> y)
          = fun x y -> y

確かにfun x y -> yとなっています。

今回はここまで。次回はリストについてです。

posted by bakemoji at 21:54| Comment(0) | TrackBack(1) | OCaml | このブログの読者になる | 更新情報をチェックする

2008年03月03日

Jim DunlopのUltexピックを買ったよ

Jim DunlopUltexピック、0.73mmと1.0mmを買いました。サイのマークがトレードマークです。ふだんはTerry Gouldの黒いピック(0.8mm。鳥のマーク)かJim Dunlopの黒いTortexピック(0.73mm。カメのマークのやつです)を使用しているのですが、ちょっと目先を変えてみようということで買ってみました。ClaytonのUltexピックとどちらにしようかで迷ったのですが、エッジの処理が滑らかなJim Dunlop製を選びました。

音に関しては、UltexはTerry GouldやTortexに比べて高音が良く出ているように感じました。驚いたのは、Terry GouldやTortexに比べると明らかにつるつるすべすべした表面なのに、実際に演奏するとなぜか一番滑りにくいという点です。手に吸い付く感触。

なかなか良い感触なのでしばらく使ってみようと思います。

ラベル:ギター
posted by bakemoji at 22:59| Comment(0) | TrackBack(1) | ギター | このブログの読者になる | 更新情報をチェックする

2008年03月02日

OCamlのお勉強 その5 〜カリー化、高階関数、匿名関数〜

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~」を読んでの勉強記録です。

カリー化によって引数を2つ以上とる関数を表現できる。また、カリー化によって表現された関数は引数の部分適用ができる。

# let concat_string s1 s2 = s1 ^ " " ^ s2;;
val concat_string : string -> string -> string = <fun>
# concat_string "Hello" "World!";;
- : string = "Hello World!"
# let greet = concat_string "Hello";;
val greet : string -> string = <fun>
# greet "John.";;
- : string = "Hello John."
# greet "Anne.";;
- : string = "Hello Anne."

文字列を2つ受け取る関数concat_stringに1つだけ文字列を与えると、文字列を1つ受け取る関数を返しています。concat_stringの型に注目すると、

string -> string -> string

になっています。これは

(* stringを受け取ってstring -> stringを返す型 *)
string -> (string -> string)

と読めます。実際、greetの型は

string -> string

になっています。これを部分適用というそうです。前回、末尾再帰関数を書くために2引数の関数を何の気なしに定義していましたが、これはカリー化を使用した表現だったようです。

高階関数を定義できる。

# let rec aggregate_n f s n =
    if n = 0 then s
    else f (aggregate_n f s (n - 1)) n;;
val aggregate_n : ('a -> int -> 'a) -> 'a -> int -> 'a = <fun>
# let add a b = a + b;;
val add : int -> int -> int = <fun>
# aggregate_n add 0 10;;
- : int = 55

aggregate_nは1からnまでの数について、初期値をsとして関数fで集約していく関数です。fは「どのように集約していくか」を決める関数となります。fにsumを渡せば1からnまでの数を足すことになります。

C#では似た機能としてデリゲートがありますね。こちらの場合、カリー化と組み合わせることでいろいろできそうです。

匿名関数を作成できる。匿名関数はfun (引数リスト) -> (式)と書く。

# let multiply = fun x y -> x * y;;
val multiply : int -> int -> int = <fun>
# aggregate_n multiply 1 10;;
- : int = 3628800
# aggregate_n (fun s n -> s + n) 0 10;;
- : int = 55
# aggregate_n (fun s n -> s * n) 1 10;;
- : int = 3628800

これはC#(〜2.0)でいうところの匿名デリゲートのようなものですね。匿名関数もまた1つの値なので、変数を匿名関数に束縛することができるというのも面白いです。上記のコード例では変数multiplyを匿名関数に束縛しています。いったん束縛してしまえば、あとは通常の関数名として使用できます。

今回はここまで。次回は多相と型推論についてです。

posted by bakemoji at 00:20| Comment(0) | TrackBack(0) | OCaml | このブログの読者になる | 更新情報をチェックする

2008年02月29日

OCamlのお勉強 その4 〜再帰関数〜

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~」を読んでの勉強記録です。

再帰関数の定義ではletの後にrecを付ける。コメントは(**)で囲む。

# let rec sum n = (* 1からnまでの合計 *)
    if n = 0 then 0
    else n + sum (n - 1);;
val sum : int -> int = <fun>
# sum 10;;
- : int = 55
# let rec fib n = (* n項目のフィボナッチ数を求める *)
  if n = 1 || n = 2 then 1 else fib (n - 1) + fib (n - 2);;
val fib : int -> int = <fun>
# fib 7;;
- : int = 13

関数内で変数や関数を定義できる。

# let fib n = (* 改良版fib *)
    let rec fib' n =
      if n = 1 then (1, 0)
      else let (y, x) = fib' (n - 1) in (y + x, y) in
    let (a, _) = fib' n in
    a;;
val fib : int -> int = <fun>

再帰させる場合はrecが必要というのが変わっています。もともとlet定義は左辺の変数を右辺では使えないので、再帰的に使えるようにするためにrecで明示するというのは筋が通っている気がします。

末尾再帰の最適化により、末尾呼び出しのみの関数は一定量以上のスタックを消費しない。

# let rec tail_sum1 n a = (* 末尾再帰sumその1。nから1までaに足しこむ *)
    if n = 0 then a
    else tail_sum1 (n - 1) (a + n);;
val sum : int -> int -> int = <fun>
# let tail_sum2 n = (* 末尾再帰sumその2。1からnまでaに足しこむ *)
    let rec tail_sum2' i a =
      if i > n then a
      else tail_sum2' (i + 1) (a + i) in
    tail_sum2' 1 0;;
val tail_sum2 : int -> int = <fun> 
# sum 1000000;;
Stack overflow during evaluation (looping recursion?).
# tail_sum1 1000000 0;;
- : int = -363189984
# tail_sum2 1000000;;
- : int = -363189984

sumではスタックオーバフローの例外が出ていますが、2つのtail_sumはしっかり計算しています(ただし、数字が大きくなりすぎて整数オーバーフローが起きています)。また、tail_sum2'では外側のtail_sum2の引数であるnを自身の引数であるiとの比較で使用している点にも注意が必要です。

通常の再帰関数を末尾再帰にするポイントは答えの途中経過を関数の引数にすることです。sumでは再帰的なsumの結果とその時点でのnを加算するために、再帰呼び出し時のコンテキストをスタックに格納します。一方、tail_sumでは引数aとしてそれまでの結果を渡しているので再帰呼び出しの結果とその時点でのnとの計算をしないで済みます。このためスタックに呼び出し前の状態を保存しておく必要が無くなります。これが末尾再帰の最適化というものらしいです。今まで名前だけは聞いてきましたが、やっとどういうものか理解できました。

今回はここまで。次回はカリー化、高階関数、匿名関数についてです。

posted by bakemoji at 00:41| Comment(1) | TrackBack(0) | OCaml | このブログの読者になる | 更新情報をチェックする

2008年02月26日

OCamlのお勉強 その3 〜組〜

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~」を読んでの勉強記録です。

組は値を並べたものである。(値1, 値2, ... , 値n)。各値の型は独立。組もまた値なので入れ子に出来る。

# ("John", 20);;
- : string * int = ("John", 20)
# let rect = ((3, 5), (8, 10));;
val rect : (int * int) * (int * int) = ((3, 5), (8, 10))

パターンマッチングにより組の各値に変数を束縛できる。値が必要ない場合はワイルドカードパターン(_)を使用する。

# let (name, age) = ("John", 20);;
val name : string = "John"
val age : int = 20
# let (position, (width, height)) = ((3, 5), (8, 10));;
val position : int * int = (3, 5)
val width : int = 8
val height : int = 10
# let (_, y) = position;;
val y : int = 5

組からの値の取り出し方が独特です。Pythonの経験からインデックスによるアクセスの方が楽に感じますが、それだと構造があいまいになって推論しにくそうですね。パターンマッチングだと必ず値に名前がつくというのも良いと思います。

組を引数に取る関数や組を返す関数を作成可能。

# let sum_and_diff (x, y) = (x + y, x - y);;
val sum_and_diff : int * int -> int * int = <fun>
3.4.3 組を用いた関数,p43

練習問題も解いてみました。

任意の整数x、yに対し、f (sum_and_diff (x, y))が(x, y)を返すような関数f。

3.4.4 練習問題,p44
# let f (x, y) = ((x + y) / 2, (x - y) / 2);;
val f : int * int -> int * int = <fun>
# f (sum_and_diff (10, 15));;
- : int * int = (10, 15)

このくらいなら簡単に解けます。今後も練習問題のうちいくつか取り上げて解いていく予定です。

今回はここまで。次回は再帰関数についてです。

posted by bakemoji at 00:13| Comment(0) | TrackBack(0) | OCaml | このブログの読者になる | 更新情報をチェックする

2008年02月22日

OCamlのお勉強 その2 〜関数〜

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~」を読んでの勉強記録です。

関数もletで定義できる。let (関数名) (引数) = (式)。型はOCamlコンパイラによって型推論されるため明示する必要はない。

# let square x = x * x;;
val square : int -> int = <fun>
# square 10;;
- : int = 100

与えられたxを2乗した値を返す関数squareを定義しています。コンパイラからの応答は「squareはint -> int型の関数」となっています。*からxはintであり、評価結果もまたintであると推論しているようです。

if式により条件分岐が可能。条件式はbool型の値(trueまたはfalse)を返す式であり、thenのあとの式とelseのあとの式は同じ型の値を返さなければならない。

# let x = 10;;
val x : int = 10
# if x < 5 then "less than 5" else "more equal than 5";;
- : string = "more equal than 5"
# let s = "hello";;
val s : string = "hello"
# if s = "hello" then "equal" else "not equal";;
- : string = "equal"

if式は式なので必ず値を返さなければなりません。つまり、else節が不可欠ということです。OCamlは式中心というのはこういうところにも表れています。比較演算子は他の言語とほぼ同じです。文字列も比較できます。ただ、同値の比較に=を使うのは珍しいかもしれません。変数束縛はletを伴うので、定義と比較で=を混同しないで済むためだと思われます。

let式により局所的な定義を与えることができる。let (局所変数の束縛) in (式) 。局所変数は(式)でのみ使用でき、let式全体の値は(式)の値。

# let circumference r =
    let pi = 3.14159 in
    2.0 *. pi *. r;;
val circumference : float -> float = <fun>
# circumference 1.0;;
- : float = 6.28318

let定義内、let式内でlet式を使用できる。同名の局所変数はより近いものが使用される。また、let定義、let式ともにandで2つ以上の変数を同時に束縛できる。

# let x = let x = 3 and y = 5 in let x = x * 2 in x + y;;
val x : int = 11

独特の記法に最初は戸惑いました。特に、let式が入れ子になると慣れていない身ではかなり読みにくく感じます。考え方としては、「y = (xを使った式) ただし x = ... とする」というものに近いかもしれません。局所変数の名前がかぶった場合の判断基準は他の言語と大差ありませんね。

今回はここまで。次回は組についてです。

posted by bakemoji at 00:06| Comment(0) | TrackBack(0) | OCaml | このブログの読者になる | 更新情報をチェックする

2008年02月20日

OCamlのお勉強 その1 〜式、値、型〜

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~」を読んでの勉強記録です。

OCamlでは式が中心。式を評価すると値が得られる。値は何らかの型を持つ。OCamlでは、式を評価する前に型の整合性をチェック(型付け、型検査)する。

Ocamlには、基本的な型として整数型(int)、実数型(float)、文字型(char)、文字列型(string)がある。

# -3 * (1 - 6 / 2) mod 4;;
- : int = 2
# 2.5 *. 3.0 +. (10.0 -. 1.5) /. 2.0;;
- : float = 11.75
# 'c';;
- : char = 'c'
# "Hello World!";;
- : string = "Hello World!"
# "Hello" ^ " OCaml " ^ "World!";;
- : string = "Hello OCaml World!"

文字列は文字のリストというわけではなく、独立した型が与えられているようです。整数と実数で使う演算子が違うこと、文字列の連結には^を使うことが特徴的です。

letキーワードを使うことで変数を値に束縛することができる。

# let pi = 3.14;;
val pi : float = 3.14
# let r = 3.0;;
val r : float = 3.
# let area = r *. r *. pi;;
val area : float = 28.26
# let pi = 3.0;;
val pi : float = 3.
# let area' = r *. r *. pi;;
val area' : float = 27.

letによる変数束縛は見た目としては他の言語における変数宣言とそう変わりません。しかし、あくまで束縛であって代入ではないそうです。また、変数名に'を使えるという点も珍しいですね。

今回はここまで。次回から関数について学んでいきます。

posted by bakemoji at 00:38| Comment(0) | TrackBack(0) | OCaml | このブログの読者になる | 更新情報をチェックする

2008年02月18日

OCamlのお勉強 その0 〜準備〜

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~」を読んでの勉強記録です。

まずは環境の構築ということで、The Caml LanguageのDownloadからWindows向けのインストーラをダウンロードしてインストールしました。Windows向けにはMinGWベースとVisual C++ベースの2つがあったので、Microsoftの方をインストールしました。readmeファイルによるとVisual C++ベースのほうはバイトコードインタプリタの速度がMinGWベースのものに比べて70%ほどだったり、コンパイル時にCコードとリンクさせるにはVisual C++のコンパイラが必要だったりするようです。インストール自体は簡単で、実行ファイルへのパスも通しておいてくれます。

この本では、対話式コンパイラを使ってコード例を示しています。対話式コンパイラはocaml.exeです。対話式コンパイラでは

# 1 + 2;;
- : int = 3

のように#のあとに続けてプログラムを入力します。;;が区切りとなり、そこまでのプログラムが評価されてプロンプトに表示されます。

今回はここまで。次回からOCamlプログラミングに入ります。

posted by bakemoji at 01:14| Comment(0) | TrackBack(0) | OCaml | このブログの読者になる | 更新情報をチェックする

2008年02月16日

OCaml始めました

関数型言語のひとつ、OCamlの勉強を始めました。入門用の書籍が2冊ありましたが、より説明が丁寧だと感じた「プログラミング in OCaml」を購入しました。

プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~プログラミング in OCaml ~関数型プログラミングの基礎からGUI構築まで~
販売元 : Amazon.co.jp 本
価格 :

やっぱり、新しい言語の習得は楽しいですね。OCamlの勉強過程についてはブログに書いていきたいと思います。

posted by bakemoji at 00:07| Comment(0) | TrackBack(0) | OCaml | このブログの読者になる | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

この広告は90日以上新しい記事の投稿がないブログに表示されております。