Clean 2.2マニュアルの第9章から:
Clean は純粋に機能的ですが、副作用のある操作 (I/O 操作など) は許可されています。セマンティクスに違反することなくこれを実現するために、従来型にはいわゆる一意性属性が提供されています。関数の引数が一意であると示されている場合、実行時に対応する実際のオブジェクトがローカルであることが保証されます。つまり、それに対する他の参照はありません。明らかに、このような「一意のオブジェクト」の破壊的な更新は安全に実行できます。
具体的にはStart
、通常アリティ0(引数を取らない)の を*World
toからの関数にすることができ*World
ます。これは、副作用が許可されていることを意味します (副作用はもはや実際には副作用ではなく、世界に対する操作です)。
は型の一意性*
を示します。つまり、world 引数のインスタンスを 2 つ持つことはできません。たとえば、次の場合、コンパイル時に一意性エラーが発生します。World
Start :: *World -> *(*World, *World)
Start w = (w, w)
StdFile
標準 IO を使用するには、 のモジュールの関数が必要ですStdEnv
。必要になる機能は次のとおりです。
stdio :: !*World -> *(!*File, !*World)
fclose :: !*File !*World -> !(!Bool, !*World)
タイプを少し単純化しましたが、実際には class からのものですFileSystem
。世界から一意stdio
のものを開き、新しい変更された世界を返します。ワールド内のファイルを閉じ、成功フラグと変更されたワールドを返します。 File
fclose
次に、その stdio ファイルから読み書きするには、次を使用できます。
freadline :: !*File -> *(!*String, !*File)
fwrites :: !String !*File -> !*File
freadline
改行文字を含む行を文字列に読み取ります。fwrites
文字列をファイルに書き込みます。通常、stdio に書き込むときに改行文字を含めます。
それを一緒に入れて:
Start :: *World -> *World
Start w
# (io,w) = stdio w // open stdio
# io = fwrites "What is your name?\n" io // ask for name
# (name,io) = freadline io // read in name
# name = name % (0, size name - 2) // remove \n from name
# io = fwrites ("Hello, " +++ name +++ "!\n") io // greet user
# (ok,w) = fclose io w // close stdio
| not ok = abort "Couldn't close stdio" // abort in case of failure
= w // return world from Start
この#
構文は、あなたにとって初めてのことかもしれません。これは、ファイル (またはその他のもの) に同じ名前を使用できるようにする一種でlet
あり、以下を使用するよりも便利です。
Start w = w3
where
(io, w1) = stdio w
io1 = fwrites "What is your name?\n" io
(name, io2) = freadline io1
//...
(ok, w3) = fclose io10 w2
これで、が入力さloop :: *File -> *File
れるまで再帰的に自身を呼び出すヘルパー関数 を使用して、疑似コードで必要なことを実行できるはずです。q
freadline
とだけでなく、より多くの機能があります。アイデアについてはfwrites
、 を参照してください。StdFile.dcl