プログラミング

PythonとRubyとLispのコレクション処理

コレクションの処理をするとき、Pythonではリスト内包表現を使うが、Rubyではブロックを使う。
例えば、コレクションcolの各要素を10倍した新しいコレクションを作るとき、Pythonなら次のように書く。

col = [1, 2, 3, 4, 5]
[x * 10 for x in col]

Rubyなら次のように書く。

col = [1, 2, 3, 4, 5]
col.collect{|x| x * 10}

両方とも、コレクションcolの各要素をxに代入して、x*10を評価した結果を新しいコレクションにする、という意味だ。

ところで同じコレクション処理をLispではどう書くのか?
いろいろな書き方があるが、loopマクロを使うと次のように書ける。

(setf col '(1 2 3 4 5))
(loop for x in col collect (* x 10))

オブジェクト指向のRubyとはかなり異なるが、Pythonのリスト内容表現とはよく似ていると感じる。

最近読んでいるPractical Common Lispでは、Lispを使ったモダンなプログラミング手法が紹介されていておもしろい。
Lispというと、古くてマイナーな言語と思われているかもしれない。
しかし、PythonやRubyをつかって現代的な開発をしているプログラマには、Lispの柔軟性は思いのほか気に入られるのではないかと考えている。

| | コメント (0) | トラックバック (0)

プログラミングのパラダイム

プログラミング・パラダイムとは、ソフトウェアを作るときの基本的な考え方を、プログラマに与えるものだ。次のように考えるとわかりやすい。

今、一人の新卒エンジニアがいるとする。彼は会社の新入社員向けのプログラミング講座で、始めてプログラミングとC言語を学んだ。
その彼に、Pythonの入門書と次のような問題を与えてみる。

問題「0から9までの整数のうち、偶数だけをコンソールに出力するプログラムを作りなさい」

彼はたぶん、こんなコードを書くだろう。

for i in range(10):
    if i % 2 == 0:
        print i
    else:
        pass

このコードはもちろん、次のC言語のコードからの類推だ。

#include <stdio.h>

int
main()
{
        int i;
        for(i = 0; i < 10; i++) {
                if (i % 2 ==0) {
                        printf("%d\n", i);
                }
        }

        return (0);
}

彼はC言語で手続き型の考え方しか学んでいないのだから、当然だろう。
ここで彼に、さっきの問題は素直に手順として見るだけでなく、例えば次のような見方もできるだろうと伝えてみる。

問題「0から9までの整数のうち、偶数だけをコンソールに出力するプログラムを作りなさい」
 ↓
・0から9までのリストをつくる
・そこから偶数だけ抜き出して別のリストをつくる
・その偶数だけのリストをコンソールに出力する

この見方を理解できれば、その新卒エンジニアはPythonの入門書を読みつつ、次のようなコードにたどり着くだろう。

a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

b = [x for x in a if x%2==0]

for x in b:
        print x

両方のプログラムとも、結果は同じなのだが、過程が異なる。一方は問題を一連の手続きとして見ているのに対し、もう一方は問題をさらに小さな問題の連続として見ている。前者が手続き型のプログラミング・パラダイムで後者が関数型のプログラミング・パラダイムだ。

このように、パラダイムは、ある問題をみたときの捉え方、つまりその問題を解決するソフトウェアを作る時の基本的な考え方を、プログラマに与えるものだ。
いろいろな問題を臨機応変に上手く解決していくには、いろいろなパラタイムを知っていることが重要だと言える。

★WOZ★



| | コメント (0) | トラックバック (0)

Pythonのリスト内包表現とRubyのブロック

コレクションの処理をするとき、Pythonではリスト内包表現を使うが、Rubyではブロックを使う。

例えば、コレクションcolの各要素を10倍した新しいコレクションを作るとき、Pythonなら次のように書く。

col = [1, 2, 3, 4, 5]
[x * 10 for x in col]

Rubyなら次のように書く。

col = [1, 2, 3, 4, 5]
col.collect{|x| x * 10}

両方とも、コレクションcolの各要素をxに代入して、x*10を評価した結果を新しいコレクションにする、という意味だ。
違うのは、Pythonが右から左に読む文法で、Rubyが左から右に読む文法だということだ。両方の式を比べると、"x * 10"と"col"の順番が逆になっている。

Pythonに慣れているとRubyの文法には違和感があるのだが、使い始めるとすぐ慣れるようにも思う。それにRubyのブロックは面白い文法だ。

それにしても、PythonとRubyのこの順序の違いは、英語と日本語の違いに源があるのかもしれない。

★WOZ★

| | コメント (0) | トラックバック (0)

C#は新人エンジニアにも扱いやすい言語だ

もし、あなたがソフトウェアの開発マネージャで、

ソフトウェアの開発経験が0年の新卒エンジニア数人とともに、

納期3ヶ月の新規開発をしなければならないとしたら、

どうすればいいだろう?

その案件がLinuxなら、成功は難しいかもしれない。

しかし、案件がWindowsなら、やり終える可能性はある。

開発言語にはC#を選ぼう。

C#は、VisualStudioと.NETとの組み合わせで、高い生産性を実現することができる。単体テストもNUnitというフリーソフトウェアを使えるし、少し手間を加えれば、GUIの自動テストもできてしまう。

正直、マイクロソフトの言語にはそれほど期待していなかったが、C#の人を選ばないところは気に入っている。

★WOZ★

[完全版] 究極のC#プログラミング ~新スタイルによる実践的コーディング Book [完全版] 究極のC#プログラミング ~新スタイルによる実践的コーディング

著者:川俣 晶
販売元:技術評論社
Amazon.co.jpで詳細を確認する

究極のC#プログラミング 究極のC#プログラミング

販売元:楽天ブックス
楽天市場で詳細を確認する

ブログランキング・にほんブログ村へ
にほんブログ村

| | コメント (1) | トラックバック (0)

エクセルのマクロ

普段からパソコンは使いこなせていて、ワードやエクセルも仕事や学校で使っているんだけど、プログラミングとなると敷居が高いなぁ、と感じている人はわりといるのではないだろうか。

そんな人におすすめなのが、PythonやVBAだ。
とくにVBAは、エクセルを持っている人なら、追加で何かをインストールしなくても使える。それでいてプログラミングの雰囲気を感じることができる。

例えば、A1セルの文字列をシート名にするなら、

ActiveSheet.Name = Range("A1").Value

と書く。

選択シートの右側にシートを挿入するなら、

Sheets.Add After:=ActiveSheet

と書く。

「選択しているセルの値を、そのシートの名前にする」関数を作るには、

 Sub シート名を選択セルの文字に()

ActiveSheet.Name =ActiveCell.Value

 End Sub

と書く。これがVBAのプログラムだ。それをマイクロソフトは「VBAマクロ」と呼んでいる。

こんなマクロを追加していくと、エクセルファイルを、表データを書き込むだけのファイルから、表データを処理して新しい情報を産み出すソフトウェアにすることができる。

もしまだマクロを書いたことがないなら、ぜひ始めてみてほしい。プログラミングの楽しさが実感できるはずだ。

★WOZ★

エクセルマクロ事典 (日経BPパソコンベストムック) Book エクセルマクロ事典 (日経BPパソコンベストムック)

著者:日経PC21
販売元:日経BP社
Amazon.co.jpで詳細を確認する

| | コメント (0) | トラックバック (0)

Go言語のgoroutine間の同期

Go言語では、goroutineと呼ぶ軽量のコルーチンを簡便に生成できる。
そして、goroutine間の同期にはchannelを使うことができる。

goroutineの生成は簡単で、例えば関数fをgoroutine化するには、

 go f()

と書く。
channelを作るには、

 var c = make(chan int)

と書く。
channelにデータを送るには、

 c <- 0

と書く。
channelからデータを取り出すには、

 <-c

と書く。
バッファを持たないチャンネルの場合、送信が完了する前に必ず受信が起こるというルールがあり、このルールをgoroutine間の同期に使うことができる。

例えば、下記のソースコードでは、"hello, world"と表示されることが保証されている。今、このソースコードからチャンネルに関するコードを除くと、2つのgoroutine間の同期の仕組みがなくなるため、"hello, world"と表示されることが保証されなくなる。

★WOZ★

//コード ここから
package main
import "fmt"

var c = make(chan int)
var a string

func f() {
        a = "hello, world";
        <-c;
}

func main() {
        go f();
        c <- 0;
        fmt.Printf("%s\n", a);
}
//ここまで

| | コメント (0) | トラックバック (0)

Go言語のソート関数

Goで配列のソートを試してみた。
手順は以下の通りだ。

  1. newで{1, 5, 4, 2, 3}という配列(array)をつくる
  2. makeでその配列への参照(slice)をつくる
  3. 参照と配列をバインドする
  4. 参照を経由して配列をソートする

Pythonと比べると一手間多い。

★WOZ★

//コードここから
package main

import (
        "fmt";
        "sort"
)

func main() {
        s := make([]int, 10);
        a := [...]int{1, 5, 4, 2, 3};

        s = &a;

        sort.SortInts(s);

        for i:=0; i < len(s); i++ {
                fmt.Println(s[i])
        }
}
//ここまで

ブログランキング・にほんブログ村へ
にほんブログ村

| | コメント (0) | トラックバック (0)

Go言語のgoroutine間の同期(2)

Go言語では、goroutineと呼ぶ軽量のコルーチンを簡便に生成できる。
そして、goroutine間の同期にはchannelを使うことができる。

channelにはバッファありとバッファなしの二種類があり、バッファなしのchannelを使ったgoroutineの同期については以前書いた。今回はバッファありのchannelを使ったgoroutineの同期について書く。

goroutineの生成は簡単で、例えば関数fをgoroutine化するには、

 go f()

と書く。
バッファありのchannelを作るには、

 var c = make(chan int, 10)

と書く。
channelにデータを送るには、

 c <- 0

と書く。
channelからデータを取り出すには、

 <-c

と書く。
バッファありのチャンネルの場合、受信が完了する前に必ず送信が起こるというルールがあり、このルールをgoroutine間の同期に使うことができる。

例えば、下記のソースコードでは、"hello, world"と表示されることが保証されている。今、このソースコードからチャンネルに関するコードを除くと、2つのgoroutine間の同期の仕組み がなくなるため、"hello, world"と表示されることが保証されなくなる。

★WOZ★

//コード ここから
package main
import "fmt"

var c = make(chan int, 10)
var a string

func f() {
        a = "hello, world";
        c <- 0;
}

func main() {
        go f();
        <- c;
        fmt.Printf("%s\n", a);
}
//ここまで

ブログランキング・にほんブログ村へ
にほんブログ村

| | コメント (0) | トラックバック (0)

Python3.xのクロージャ

Go言語で書き、Python2.6で書き直したカウンタのコードを、さらにPython3.1で書き直してみる。

まずGo言語と比べると、Pythonは型を宣言する必要がないので、

 cnt0  = counter(0);

と書くと、初期値が0のカウンタが作られ、

 cnt10 = counter(10)

と書くと、初期値が10のカウンタが作られる。

そして、

cnt0カウンタは呼び出される度に、1, 2, 3, , , とカウントアップし、
cnt10カウンタは呼び出される度に、11, 12, 13, , ,とカウントアップする。

さて、Python2.6では内側の関数から外側のローカル変数を書き換えることができないので、クロージャを書くときには、変数ではなくリストを使った。

しかしPython3.0からは、nonlocal文を使うことで内側の関数から外側のローカル変数を書き換えられる。このため、Python3.xではGoと同様のクロージャの書き方ができる。

最後に、Python3.0ではprintが文ではなく関数なので、

print cnt0()

ではなく、

print (cnt0())

と書く。

下のコードはPython3.1用だ。

★WOZ★

//コードここから

def counter(n):

        i = n
        def func():
                nonlocal i
                i += 1
                return i
        return func

if __name__ == '__main__':
        cnt0 = counter(0)
        cnt10 = counter(10)

        print (cnt0())
        print (cnt0())
        print (cnt10())
        print (cnt10())
        print (cnt0())
        print (cnt0())
//ここまで

ブログランキング・にほんブログ村へ
にほんブログ村

| | コメント (0) | トラックバック (0)

Pythonのクロージャ

昨日のGoのコードをPythonで書き直してみる。

Pythonは型を宣言する必要がないので、

 cnt0  = counter(0);

と書くと、初期値が0のカウンタが作られ、

 cnt10 = counter(10)

と書くと、初期値が10のカウンタが作られる。

cnt0カウンタは呼び出される度に、1, 2, 3, , , とカウントアップし、
cnt10カウンタは呼び出される度に、11, 12, 13, , ,とカウントアップする。

Python2.6では内側の関数から外側のローカル変数を書き換えることができないので、クロージャを書くときには、変数ではなくリストを使う。これはGoにはない制限だ。

しかしPython3.0からは、nonlocal文を使うことで内側の関数から外側のローカル変数を書き換えられる。このため、Python3.xではGoと同様のクロージャの書き方ができる。

下のコードはPython2.6用だ。

★WOZ★

//コードここから

def counter(n):
        i = [n]
        def func():
                i[0] += 1
                return i[0]
        return func

if __name__ == '__main__':
        cnt0 = counter(0)
        cnt10 = counter(10)

        print cnt0()
        print cnt0()
        print cnt10()
        print cnt10()
        print cnt0()
        print cnt0()
//ここまで

| | コメント (0) | トラックバック (0)