プログラミング言語goを触ってみました

昨日あたりからgoというプログラミング言語が妙に目につきます。噂によると強い型付けを持つ並列処理に強い言語らしい。せっかくなのでちょっと触ってみることにしました。
まずはインストール。ここのサイトに上がっているファイルを全部落としてきます。
これらのインストール先はデフォルトで /opt 以下に設定されているので必要なディレクトリを作成してオーナーを自分にしておきます。

$ sudo mkdir /opt/nar
$ sudo mkdir /opt/april
$ sudo mkdir /opt/go
$ sudo chown ando /opt/nar /opt/april /opt/go

あとは全部展開していつも通りconfigure〜make installするだけですが一つ注意。automake系のファイルがsymlinkになっています。コマンド実行前に自分の環境にあるファイルを指すよう修正しておきましょう。
OOIO: なんかのライブラリ

$ tar -xvzf ooio-9-30-07.tgz
$ cd ooio
$ rm install-sh 
$ ln -s /opt/local/share/automake-1.11/install-sh install-sh 
$ rm depcomp
$ ln -s /opt/local/share/automake-1.11/depcomp depcomp
$ ./configure
$ make
$ make install

April: goのインストールに必要なまた別のプログラミング言語らしい

$ tar -xvzf april-9-30-07.tgz
$ cd april5
$ rm depcomp
$ ln -s /opt/local/share/automake-1.11/depcomp depcomp
$ rm elisp-comp 
$ ln -s /opt/local/share/automake-1.11/elisp-comp elisp-comp
$ ./configure
$ make
$ make install

Go: 本体です

$ tar -xvzf go-9-30-07.tgz
$ cd go
$ rm config.guess 
$ ln -s /opt/local/share/automake-1.11/config.guess ./
$ rm config.sub 
$ ln -s /opt/local/share/automake-1.11/config.sub ./
$ ./configure
$ make
$ make install

最後に必要なディレクトリにパスを通しておきます。

$ export PATH="/opt/april/bin/:/opt/go/bin:$PATH"

以上でインストールは完了。これでgoが実行できるようになりました。
それではまずgoのインストールディレクトリ内にあるTests/google.goを試しに実行してみます。ご覧の通りgoのコンパイルコマンドはgoc、コンパイルの結果として拡張子gocを持つファイルが生成されます。

$ cp /opt/go/Tests/google.go ./
$ goc google.go
 Encoding file:////Users/ando/google.goc ... ok
$ go google.goc
starting unit testgoogle
[5,5,5,3,1,4]-[2,1,1,2,9,6]=[3,1,4,0,1,8]
[5,5,5,3,1,4]-[2,1,1,2,9,8]=[3,1,4,0,1,6]
... snip ...
[6,6,6,3,7,9]-[2,7,7,2,0,5]=[3,7,9,1,7,4]
[7,7,7,5,8,9]-[1,8,8,1,0,6]=[5,8,9,4,8,3]
unit testgoogle checks out ok

何がどうなっているのか分かりませんが、何かが無事に動作したようです。言語の雰囲気を感じるためにさっそくソースを見てみます。

/*
 * WWWDOT - GOOGLE = DOTCOM
 */

google{
  import go.unit.
  import go.io.

  -- single step addition, with explicit carry in and carry out
  add:[integer,integer,integer,integer,integer]{}.
  add(I,X,Y,0,Z)::I+X+Y<10 :-- Z=I+X+Y .
  add(I,X,Y,1,Z) :-- Z=I+X+Y-10.

  -- single step subtraction, with explicit carry in and carry out
  sub:[integer,integer,integer,integer,integer]{}.
  sub(I,X,Y,0,Z) :: X-Y-I>=0 :-- Z=X-Y-I.
  sub(I,X,Y,1,Z) :-- Z=X-Y-I+10.

  -- single step permutation, pick an element and leave the rest
  pick:[list[t],t,list[t]]{}.
  pick([X,..Y],X,Y).
  pick([X,..Y],A,[X,..Z]) :- pick(Y,A,Z).

  -- specify the sum as a test on variables
  solve:[list[integer],list[integer],list[integer]]{}.
  solve([W,W,W,D,O,T],[G,O,O,G,L,E],[D,O,T,C,O,M]) :-
      R10 = [0,1,2,3,4,5,6,7,8,9],   -- start out with all the digits
      pick(R10,T,R9),
      pick(R9,E,R8),
      pick(R8,M,R7),                 -- it makes a difference to performance to test quickly
      sub(0,T,E,C1,M),               -- T-E=M
      pick(R7,O,R6),
      pick(R6,L,R5),
      sub(C1,O,L,C2,O),              -- O-L-C1=O
      pick(R5,D,R4),
      pick(R4,G,R3),
      pick(R3,C,R2),
      sub(C2,D,G,C3,C),              -- D-G-C2=C
      pick(R2,W,_),
      sub(C3,W,O,C4,T),              -- W-O=T
      sub(C4,W,G,0,D).

  -- verify that we got the right answer. Too lazy to do by hand
  -- so, this is long subtraction
  chck:[list[integer],list[integer],list[integer],integer]{}.
  chck([a,..A],[b,..B],[c,..C],cI) :-   -- A*-B*=C*
      ( a-b-cI >= 0 ?                   -- check for carry out
          a-b-cI = c,
          chck(A,B,C,0)
      | a-b-cI+10=c,
        chck(A,B,C,1)
      ).
  chck([],[],[],0).

  check:[list[integer],list[integer],list[integer]]{}.
  check(A,B,C) :-
      chck(reverse(A),reverse(B),reverse(C),0). -- we need to reverse the lists, because long subtraction is RtoL
      
  testgoogle:[]@=harness.
  testgoogle<=harness.                          -- use our test harness
  testgoogle..{
    doAction() ->
        solve(A,B,C) *>
        stdout.outLine(A.show()<>"-"<>B.show()<>"="<>C.show()).
        
    doPred() :-
        solve(A,B,C),
        check(A,B,C).
  }.

  main(_) ->
      checkUnit(testgoogle).
}.

引数のパターンマッチで処理が変わってるんでしょうか?Haskelってこんな感じでしたっけ?普通のWeb系プログラマの私があんまり目にすることのない感じです。とりあえずリファレンスによるとgoの特徴は次のようなものだそうです。

といっても例が悪かったのかオブジェクト指向はどのへんにあるのか分かりません・・・。関数型と論理型はなんとなく分かるような・・・。
正直全然ピンと来ないのでとりあえずHello Worldを自作してみます。

helloworld {
  import go.io.
  main(_) ->
    stdout.outLine("Hello, Go! World").
}.
$ goc helloworld.go
 Encoding file:////Users/ando/helloworld.goc ... ok
$ go helloworld.goc
Hello, Go! World

まぁ、Hello Worldくらいなら何やってるか分からんでもない感じです。なんかだんだんどうオチをつければいいのか分からなくなって来ました。Hello Worldも動いたことだしこのまま投げっ放すことにします。おわり。

・・・一応書いておきますが、分かってやってます