main関数

突然main関数なんて出したけど、これの必要性について説明しよう。

今までは、関数を適当に定義して、対話式インタプリタで呼び出していた。
でも、独立した実行形式のファイルを作った場合はどうだろう?

windowsなどのOSは役所仕事なので、haskellのコードが持つ関数を理解してくれない。
だから、こちらから何を評価すれば良いか教えなくてはいけない。
そのための関数がmainなんだ。実行形式にすると、まずmain関数が呼び出される。

それじゃあ、main関数を持つソースコードを作ってみよう。
ちなみに、main関数は基本の関数なので、これを利用するだけのコードならモジュールの指定は要らない。
勝手にMainというモジュールだと解釈してくれるんだ。
それと、mainを用いたソースは、名前をmainにすると意味が分からないから、適当に名前を付けてね。
ここではhello.hsにするよ。

main = [[print]] "Hello, world!"

とりあえずコンパイルして実行形式を作ってみよう。
ここでは、コンソールを行き来するのが面倒なので、GHCiから呼び出すね。
:!コマンドを使うと、システムのコンソールコマンドを使えるんだ。

Prelude> :!ghc -o hello hello.hs

hello.exeのような実行形式が出来たかな? サイズは結構大きいね(汗
まあ、実行してみよう。

Prelude> :!hello
"Hello, world!"

うん、問題ないね。

さて、このプログラムは1文だけだから良いけど、もっと複雑なプログラムはどうしよう?
関数の定義は基本的に1文だから、これじゃあ作れないぞ?

ということは当然なくて、こういう風に書けばいいらしい。

main = do print "Hello, World!"
          print "Welcome to haskell!"

printの頭は揃ってないといけないよ。そういう失敗は良くやるから、ちょっと動かしてエラー文を確認しておこう。
doについての情報はGHCiでは見つからない。後で調べてみよう。
ともあれ、これをコンパイルして実行するとこうなる。

*Prelude> :!ghc -o hello print.hs
*Prelude> :!hello
"Hello, World!"
"Welcome to haskell!"

doを使うと、命令文のようになるね。
これでmainが2行以上になるプログラムを作れるようになった。
他の言語では普通だけど、関数型言語は喜ぶところね。

今度はGHCiに戻って、型を分析しよう。
と、ここで関数を一つ紹介。他のサイトでは最初にでてくると思うけど、

Prelude> putStrLn "banana"
banana

putStrLnは文字列の内容を表示するんだ。
printに比べて大文字を使ってたり複雑っぽいから、説明を後回しにしてた。
これも使って、次のモジュールを作ろう。

module Test3 where

f1 = print "Hahaha!"

f2 = do print "Hehehe!"

f3 = do putStrLn "Hohoho!"
        print 1023

g1 m1 m2 = do putStrLn m1
              putStrLn m2

g2 a b = do print a
            print b

実行結果は大体予想通りなので省略するよ。型を見てみよう。

*Test3> :t f1
f1 :: IO ()
*Test3> :t f2
f2 :: IO ()
*Test3> :t f3
f3 :: IO ()
*Test3> :t g1
g1 :: String -> String -> IO ()
*Test3> :t g2
g2 :: (Show a1, Show a) => a -> a1 -> IO ()

printの返り値がIO ()で、他の書き方をしてもIO ()になるようだね。
引数は関係ないようだ。

mainは、このように返り値がIO aになる関数じゃないといけないんだ。
試しに、そうでない関数にしてコンパイルすると、

main = "fail"

Prelude> :!ghc -o fail fail.hs

fail.hs:1:0:
    Couldn't match `IO a' against `[Char]'
      Expected type: IO a
      Inferred type: [Char]
    In the first argument of `GHC.TopHandler.runMainIO', namely `main'
    When checking the type of the main function `main'

IO aでないとダメだって注意される。

ここで、Cを知っている人は比べてみて欲しい。

#include <stdio.h>
int main(void){printf("ゴッゴル");printf("ヤッヒョイ");return 0;}
//動くかな、これ。

Cの関数も、文字を表示するだけのプログラムで、使いもしない返り値を要求される。
Cの場合は、main関数の返り値の型は気にしないけど、haskellの場合はIO型になるんだ。

IO型というのはいまいち分からないけど、普通の型とは違うようだね。
次はその辺りを調べてみようかな。

と、この先は、さんざん分岐した方の説明も見てないと分からなくなるから、選択肢を拡げるのは一時停止。
他の経路と合流して次の段階に進もう。次は入出力にしよう。

タグ:

+ タグ編集
  • タグ:
最終更新:2007年09月27日 06:30