Iconは、「目標指向実行」という概念に基づいた非常に高水準なプログラミング言語です。コード内の式は、結果とともに「成功」を返すか、有効な結果がないことを示す「失敗」を返します。与えられた式の成功と失敗は、その後の処理の方向を決定するために使用されます。一方、従来の言語では、同じ目的を達成するためにプログラマが記述したブール論理を使用するのが一般的です。Iconでは基本的な制御構造のロジックが暗黙的に記述されることが多いため、一般的なタスクはより少ないコードで完了できます。
Iconは、ベル研究所でSNOBOL言語の開発に大きく貢献したラルフ・グリスウォルドによって設計されました。SNOBOLは文字列処理言語で、1970年代初頭の基準からすると、構文は時代遅れと見なされていました。アリゾナ大学に移った後、彼はSL5でSNOBOLの基本的な概念をさらに発展させましたが、その結果は失敗だったと考えました。これが、SNOBOLのような言語の短くても概念的に密度の高いコードと、CやPascalのようなALGOLに影響を受けた言語のより馴染みのある構文を融合させた、大幅に改良されたIconの開発につながりました。
Iconは、その着想源となった言語と同様に、文字列やテキストパターンの管理を主な用途としています。文字列操作は、例えば「world」の中から「the」を見つけるなど、しばしば失敗します。ほとんどの言語では、無効な結果を使用しないように、テストと分岐処理が必要になります。Iconでは、こうしたテストのほとんどが不要となり、記述するコード量を削減できます。複雑なパターン処理も、Perlのような専用言語と同様に、簡潔な数行のコードで実現できますが、他のALGOL系言語のユーザーには馴染みのある、より関数指向の構文を維持しています。
Icon はオブジェクト指向ではありませんが、1996 年に Idol というオブジェクト指向の拡張機能が開発され、最終的にUniconになりました。また、そのシンプルなジェネレータは他の言語にも影響を与え、特に影響力がありました。Icon のジェネレータはPython言語の大きなインスピレーションとなりました。[ 3 ]
SNOBOL の最初の取り組みは、後に SNOBOL1 として知られるようになり、1962 年秋にベル研究所プログラミング研究部門で開始されました。[ 4 ]この取り組みは、多項式の操作、記号積分、マルコフ連鎖の研究に SCL 言語を使用しようとした際の不満に対する反応でした。部門長のチェスター リーによって書かれた SCL は、処理速度が遅く、構文が低レベルだったため、単純なプロジェクトでも大量のコードが必要でした。COMIT 言語を少し検討した後、6 人の部門のメンバーであるイヴァン ポロンスキー、ラルフ グリスウォルド、デビッド ファーバーは、これらの問題を解決するために独自の言語を書くことにしました。[ 5 ]
最初のバージョンは1963年初頭にIBM 7090上で動作し、夏までには完成してベル社全体で使用されるようになった。これにより、すぐにSNOBOL2が登場し、多数の組み込み関数と外部アセンブリ言語コードへのリンク機能が追加されました。SNOBOL2は1964年4月にリリースされ、主にベル社内で使用されましたが、プロジェクトMACでも一部使用されました。システム関数の導入は、主にユーザー定義関数の必要性を示すものであり、これは1964年7月にリリースされたSNOBOL3の主要な機能でした。[ 6 ]
SNOBOL3 の導入は、ベル研究所のコンピューティング部門における大きな変化と時期を同じくしており、その中には SNOBOL の書き直しが必要となる新しいGE 645メインフレームの追加も含まれていました。代わりに、チームは仮想マシン上で動作する新しいバージョン、SNOBOL Intermediate Language の SIL を作成することを提案し、十分なパワーを持つプラットフォームであればどこにでも簡単に移植できるようにしました。この提案は 1965 年 9 月に SNOBOL4 として採用されました。この時点で、1966 年 8 月に言語を大幅に改良したバージョンの計画が浮上しました。[ 7 ]言語に関するさらなる作業は 1960 年代の残りの期間を通じて続けられ、特に後のバージョンでは、テーブルと呼ばれる連想配列型が追加されました。
グリズウォルドは1971年8月にベル研究所を離れ、アリゾナ大学の教授となった。[ 8 ]彼は当時、研究ツールとしてSNOBOL4を導入した。[ 9 ]彼はSNOBOLのサポートと発展を継続するために、国立科学財団から助成金を受けた。[ 10 ]
SNOBOLは1960年代初頭に開発された言語であるため、その構文にはFORTRANやCOBOLなどの初期のプログラミング言語の特徴が見られます。特に、これらの言語の多くはパンチカードに入力されていたため、列レイアウトが自然なものであったことから、SNOBOLは列に依存しています。さらに、制御構造はブロックの使用ではなく、コードの分岐にほぼ完全に依存していました。ブロックはALGOL 60の導入後に必須の機能になりつつありました。彼がアリゾナに移住した頃には、SNOBOL4の構文は絶望的に時代遅れになっていました。[ 11 ]
グリズウォルドは、if/then のような従来のフロー制御構造を使用して SNOBOL の基本的な成功/失敗の概念を実装する取り組みを開始しました。これが SL5、つまり「SNOBOL Language 5」の略となりましたが、結果は満足のいくものではありませんでした。[ 11 ] 1977 年、彼は新しいバージョンを検討するために言語に戻りました。彼は SL5 で導入された非常に強力な関数システムを放棄し、より単純なサスペンド/レジュームの概念を採用し、SNOBOL4 の自然な後継となる新しい概念を次の原則に基づいて開発しました。[ 11 ]
新しい言語は当初SNOBOL5として知られていましたが、基本的な概念以外はSNOBOLとは大きく異なっていたため、最終的には新しい名前が望まれました。「C」への一種のオマージュとして「s」を検討しましたが、その名前を使用した文書の組版に問題があったため、最終的に放棄されました。一連の新しい名前が提案され、放棄されました。Irving、bard、および「The Language」の「TL」です。この頃、Xerox PARCがグラフィカルユーザーインターフェースに関する研究を発表し始め、「icon」という用語がコンピュータ用語集に入り始めました。最初に「icon」に名前を変更する決定がなされ、最終的に「Icon」が選択されました。[ 11 ] [ a ]
Icon言語はALGOLクラスの構造化プログラミング言語から派生しており、CやPascalに似た構文を持っています。IconはPascalに最も似ており、:=代入構文、procedureキーワード、および同様の構文を使用しています。一方、Iconは実行グループを構造化するためにCスタイルの波括弧を使用し、プログラムはと呼ばれるプロシージャを実行することから始まりますmain。[ 13 ]
Icon は多くの点で、ほとんどのスクリプト言語(および、それらが由来するSNOBOLや SL5) と共通の機能を持っています。変数を宣言する必要がなく、型は自動的にキャストされ、数値は自動的に文字列に変換され、また元に戻すことができます。 [ 14 ]多くのスクリプト言語に共通するもう 1 つの機能は、行末文字がないことです。Icon では、セミコロンで終わらない行は、意味が通じる場合は暗黙のセミコロンで終了します。[ 15 ]
プロシージャはIconプログラムの基本的な構成要素です。Pascalの命名規則を使用していますが、C言語の関数のように動作し、値を返すことができます。Iconにはキーワードはありませんfunction。[ 16 ]
SNOBOLの重要な概念の1つは、マジックナンバーやその他の手法を使用するのではなく、言語のプリミティブとして「成功」または「失敗」を返す関数である。[ 17 ] [ 18 ]
例えば、ある文字列内の部分文字列の位置を返す関数は、ほとんどの言語ランタイムシステムでよく見られるルーチンです。JavaScript では、「Hello, World!」プログラム内の「World」という単語の位置を見つけるには、を使用し、変数 に 7 を返します。代わりに を要求すると、検索語が文字列に含まれていないため、コードは「失敗」します。JavaScript では、ほとんどの言語と同様に、これはマジックナンバーを返すことで示され、この場合は -1 が返されます。[ 19 ]position="Hello, World".indexOf("World")positionposition="Hello, World".indexOf("Goodbye")
SNOBOL では、このような失敗は特別な値を返します&fail。SNOBOL の構文は、操作の成功または失敗に直接作用し、別のテストを記述することなく、ラベル付きコードのセクションにジャンプします。たとえば、次のコードは "Hello, world!" を 5 回出力します。[ 20 ]
* SNOBOL プログラムで「Hello World」と出力します。I = 1 LOOP OUTPUT = "Hello, world!" I = I + 1 LE ( I , 5 ) : S ( LOOP ) ENDLEループを実行するには、インデックス変数 I に対して小なり演算子が呼び出され、それがS成功した場合、つまり I が 5 未満であれば、指定されたラベルに分岐して処理LOOPが続行されます。[ 20 ]
Icon は、成功または失敗に基づくフロー制御の概念を維持しつつ、言語をさらに発展させた。 1 つの変更点は、ラベル付きのような分岐を、1960 年代後半にコンピュータ業界を席巻していた構造化プログラミングGOTOスタイルに合わせてブロック指向構造に置き換えたことである。 [ 11 ] 2 つ目の変更点は、「失敗」を呼び出しチェーンに沿って渡すことができるようにし、ブロック全体が全体として成功するか失敗するかが決まるようにしたことである。これは Icon 言語の重要な概念である。従来の言語では、ブール論理に基づいて成功または失敗をテストし、その結果に基づいて分岐するコードを含める必要があったが、このようなテストと分岐は Icon コードに固有のものであり、明示的に記述する必要はない。[ 21 ]
例えば、 Javaプログラミング言語で書かれたこのコードを考えてみましょう。このコードは、関数を呼び出してread()(以前に開いた)ファイルから文字を読み込み、その結果を変数に代入しa、writeその値をa別のファイルにコピーします。結果として、あるファイルを別のファイルにコピーすることになります。readは最終的にファイルから読み込む文字がなくなる可能性があり、場合によっては最初の呼び出しでそうなると、はa不確定な状態になり、がヌルポインタ例外をwrite引き起こす可能性があります。これを回避するため、はこのような状況で特別な値(ファイルの終端)を返します。そのため、これを回避するには明示的なテストが必要です。readEOFwrite
while (( a = read ()) != EOF ) { write ( a ); }対照的に、Icon では、read()関数はテキスト行または を返します&fail。&failは、 の単なる類似物ではなくEOF、言語では、コンテキストに応じて「処理を停止する」または「失敗ケースを実行する」という意味として明示的に理解されます。Icon での同等のコードは次のとおりです。[ 18 ]
これは、「read が失敗しない限り write を呼び出し、そうでなければ停止する」という意味です。[ 18 ] Java の例のようにマジックナンバーに対するテストを指定する必要はなく、これは暗黙的に行われるため、結果としてコードが簡略化されます。成功と失敗は呼び出しチェーンを通じて渡されるため、関数呼び出しを他の関数呼び出しの中に埋め込むことができ、ネストされた関数呼び出しが失敗すると停止します。たとえば、上記のコードは次のように簡略化できます。[ 22 ]
このバージョンでは、read呼び出しが失敗した場合、write呼び出しは失敗し、while停止します。[ 22 ] Icon の分岐およびループ構造はすべて、プログラマが提供する任意のブール値テストではなく、内部のコードの成功または失敗に基づいています。 は、その「テスト」が値を返す場合にブロックをif実行し、を返す場合はブロックを実行するか、次の行に移動します。同様に、 は、失敗を受け取るまでブロックの呼び出しを続けます。Icon はこの概念を目標指向実行と呼んでいます。[ 23 ]thenelse&failwhile
成功と失敗の概念と例外の概念を対比することが重要です。例外は予期される結果ではなく、異常な状況です。Icon における失敗は予期される結果です。ファイルの末尾に到達することは予期される状況であり、例外ではありません。Icon には従来の意味での例外処理はありませんが、例外のような状況で fail がよく使用されます。たとえば、読み取ろうとしているファイルが存在しない場合、read特別な状況を示すことなく失敗します。[ 18 ]従来の言語では、これらの「その他の条件」を自然に示す方法はありません。追加のマジックナンバーが使用される場合もありますが、より一般的には例外処理を使用して値を「スロー」します。たとえば、Java コードでファイルが見つからない場合を処理するには、次のようになります。
try { while (( a = read ()) != EOF ) { write ( a ); } } catch ( Exception e ) { // 何らかのエラーが発生した場合は、この catch を使用してループを終了します}このケースでは、EOF とその他のエラーの 2 つの比較が必要です。Java では Icon のように例外を論理要素として比較することができないため、try/catch代わりに長い構文を使用する必要があります。また、try ブロックは例外が発生しない場合でもパフォーマンスの低下を招くため、 Icon では通常このような分散コストを回避しています。
Icon は、従来のブールテストを実行するために、この同じ目標指向メカニズムを使用しますが、微妙な違いがあります。 のような単純な比較は、ほとんどの言語のように「条件式の評価結果が または真の値を返す場合」を意味するのではなく、「条件式が成功し、失敗しない場合」のような意味になります。この場合、比較が真であれば演算子は成功します。 は、式が成功した場合はその節を呼び出し、失敗した場合は (存在する場合) または次の行を呼び出します。結果は、他の言語で見られる従来の if/then に似ており、が より小さい場合にを実行します。微妙な点は、同じ比較式をどこにでも配置できることです。たとえば、次のようになります。ifa<bthenwrite("a is smaller than b")<ifthenelseifthenab
もう 1 つの違いは、<この演算子が成功した場合、その 2 番目の引数を返すことです。この例では、 のb値が より大きい場合は の値が書き込まれa、そうでない場合は何も書き込まれません。これは厳密にはテストではなく、値を返す演算子であるため、 や などを組み合わせることができますif a < b < c。[ 22 ] は、ほとんどの言語で のような 2 つの不等式の論理積として記述する必要がある一般的なタイプの比較ですif (a < b) && (b < c)。
目標指向実行の重要な側面は、プロシージャが失敗した場合にプログラムが以前の状態に戻る必要がある場合があることです。これはバックトラッキングと呼ばれるタスクです。たとえば、変数を開始位置に設定してから値を変更する可能性のある操作を実行するコードを考えてみましょう。これは、たとえば文字列スキャン操作でよく見られるもので、スキャン中にカーソルが文字列内を進みます。プロシージャが失敗した場合、その変数のその後の読み取りでは、内部で操作されていた状態ではなく、元の状態が返されることが重要です。このタスクのために、Icon には可逆代入演算子、<-および可逆交換演算子、があります<->。たとえば、より大きな文字列の中からパターン文字列を検索しようとするコードを考えてみましょう。
このコードはi、検索の開始位置である10に移動することから始まります。しかし、検索がfind失敗すると、ブロック全体が失敗し、望ましくない副作用として、の値が10のまま残ってしまいます。iをに置き換えることで、ブロックが失敗した場合にを以前の値にリセットする必要があることを示します。これにより、実行におけるアトミック性と同様の効果が得られます。i := 10i <- 10i
Icon の式は単一の値を返すことができます。たとえば、5 > xx の値が 5 未満であれば評価して x を返し、そうでなければ失敗して値を返しません。Icon には、成功または失敗をすぐに返さず、呼び出されるたびに新しい値を返すプロシージャの概念も含まれています。これらはジェネレータと呼ばれ、Icon 言語の重要な部分です。Icon の用語では、式または関数の評価によって結果シーケンスが生成されます。結果シーケンスには、式または関数によって生成できるすべての可能な値が含まれます。結果シーケンスが尽きると、式または関数は失敗します。
Icon を使用すると、任意のプロシージャが単一の値または複数の値を返すことができます。これらの値はfail、、returnおよびsuspendキーワードを使用して制御されます。これらのキーワードのいずれかが欠落しているプロシージャは を返します&fail。これは、endプロシージャの実行が に達するたびに発生します。例:
を呼び出すとf(5)1 が返されますが、 を呼び出すf(-1)と が返されます。これは、たとえばが失敗して の操作を中断するため、 が何も出力しないなど&fail、予期しない動作につながる可能性があります。[ 24 ]write(f(-1))fwrite
プロシージャをジェネレータに変換するには、キーワードを使用します。これは、「この値を返し、再度呼び出されたときに、この時点から実行を開始する」という意味です。この点では、C と の概念suspendの組み合わせのようなものです。たとえば、次のようになります。 [ 18 ]staticreturn
iは、から始まり a で終わる一連の数値を返すジェネレータを作成しj、&failその後返します。[ b ]は実行を停止し、状態をリセットせずにsuspend iの値を返します。同じ関数が再度呼び出されると、実行はその時点から以前の値で再開されます。この場合、 が実行され、while ブロックの開始までループし、次の値を返して再び中断します。これは が失敗するまで続き、その時点でブロックを終了し、 を呼び出します。これにより、イテレータを簡単に構築できます。[ 18 ]ii +:= 1i <= jfail
もう一つの発電機型発電機はオルタネータで、ブールor演算子に似た外観と動作をします。例えば:
これは「yがxまたは5より小さい場合…」と言っているように見えますが、実際にはリストの末尾に達するまで値を返すジェネレーターの省略形です。リストの値は、この場合は操作に「注入」されます<。したがって、この例では、システムはまずy < xをテストします。xがyより大きい場合はxの値が返され、テストは合格となり、yの値が節に書き出されますthen。しかし、xがyより大きくない場合は失敗し、オルタネータはy < 5を実行します。このテストが合格すると、yが書き出されます。yがxまたは5のどちらよりも小さい場合、オルタネータはテストが尽きて失敗し、が失敗しif、はwrite実行されません。したがって、yの値がxまたは5より小さい場合は、yの値がコンソールに表示され、ブール値の目的が達成されますor。関数は、パラメータの評価が成功しない限り呼び出されないため、この例は次のように短縮できます。
内部的には、オルタネータは単なる関数ではなくor、任意の値のリストを構築するためにも使用できます。これは、次のような任意の値を反復処理するために使用できます。
整数のリストは多くのプログラミング環境でよく見られるため、Iconにはアドホックな整数ジェネレータtoを構築するためのキーワードも含まれています。
短縮形:
アイコンは厳密に型付けされていないため、オルタネータリストには異なるタイプのアイテムを含めることができます。
これは、1、"hello"、そしてxの値によっては5を書き込む可能性があります。
同様に、論理積演算子, &, はブール演算子と同様の方法で使用されますand。[ 25 ]
このコードは、ItoJx に代入される初期値 0 を呼び出し、返します。次に、論理積の右辺を実行し、 が0 と等しいので、その値を出力します。次に、ジェネレータを再度呼び出し、x に 1 を代入しますが、右辺が失敗し、何も出力されません。結果として、0 から 10 までのすべての偶数のリストが得られます。[ 25 ]x % 2ItoJ
ジェネレータの概念は、文字列操作と組み合わせると特に有用かつ強力であり、Iconの全体的な設計における主要な基盤となっています。indexOf多くのプログラミング言語に見られる操作を考えてみましょう。この関数は、ある文字列を別の文字列の中に探し出し、その位置を示すインデックスを返します。見つからない場合はマジックナンバーを返します。例えば、次のようになります。
s = "全世界は舞台。そして、すべての男と女はただの役者にすぎない" ; i = indexOf ( "the" , s ); write ( i );これは文字列をスキャンしs、「the」の最初の出現箇所を見つけて、そのインデックス(この場合は4)を返します。ただし、文字列には「the」が2回出現するため、2番目の例を返すには別の構文を使用します。
j = indexOf ( "the " , s , i + 1 ); write ( j );これは、位置5からスキャンを開始するように指示するため、以前に見つかった最初のインスタンスとは一致しません。ただし、「the」の2番目のインスタンスが存在しない可能性があり、最初のインスタンスも存在しない可能性があるため、戻り値はindexOf一致がないことを示すために使用されるマジックナンバー-1と比較する必要があります。すべてのインスタンスの位置を出力する完全なルーチンは次のとおりです。
s = "全世界は舞台。そして男も女もただの役者に過ぎない" ; i = indexOf ( "the" , s ); while i != - 1 { write ( i ); i = indexOf ( "the" , s , i + 1 ); }Iconでは、これに相当するものfindがジェネレーターなので、同じ結果をたった1行で作成できます。
もちろん、入力のある時点以降の文字列を検索したい場合もあります。例えば、最初の4列に行番号、スペース、そしてテキスト行が含まれているテキストファイルをスキャンする場合などです。目標指向実行を使用すると、行番号をスキップできます。
位置は、位置 5 の後に「the」が出現する場合にのみ返されます。それ以外の場合は比較が失敗し、書き込み失敗が渡され、書き込みは行われません。
この演算子は、ジェネレーターによって返されたすべての項目をループし、失敗した場合に終了するという点で、everyに似ています。 [ 24 ]while
everyとには重要な違いがありますwhile。 はwhile最初の結果が失敗するまで再評価しますが、 はeveryジェネレータから次の値を取得します。は実際にはSmalltalkeveryのブロックと同様の方法で関数に値を注入します。たとえば、上記のループは次のように書き換えることができます。[ 24 ]
この場合、iからjまでの値が注入されsomeFunction、(場合によっては)複数の出力行が書き込まれます。[ 24 ]
Iconには、スタックやキューとしても使用できるリスト、テーブル(他の言語ではマップや辞書とも呼ばれる)、セットなど、いくつかのコレクション型が含まれています。Iconではこれらを構造体と呼んでいます。コレクションは本質的にジェネレーターであり、バン構文を使用して簡単に呼び出すことができます。例えば、次のようになります。
前述の例で示した障害伝播を利用することで、テストとループを組み合わせることができます。
リストコレクションはジェネレーターであるため、これはさらにバン構文で簡略化できます。
この場合、 の bang によってwriteIcon は配列からテキストの行を 1 行ずつ返し、最後に失敗します。 は、標準入力から 1 行を読み込む&inputジェネレータベースの類似物なので、ファイルが終了するまで行の読み込みを続けます。read!&input
Iconは型を持たないため、リストにはあらゆる種類の値を含めることができます。
項目には他の構造を含めることができます。より大きなリストを作成するために、Icon にはlistジェネレータが含まれています。これは、「word」のコピーが 10 個含まれるリストを生成します。他の言語の配列と同様に、Icon では、位置によって項目を検索できます。たとえば、配列スライスが含まれているため、他のリストの要素から新しいリストを作成できます。たとえば、は、「tabby」と 2002 を含む aCat という名前の新しいリストを生成します。i := list(10, "word")weight := aCat[4]aCat := Cats[2:4]
テーブルは基本的に、整数ではなく任意のインデックスキーを持つリストです。
このコードは、未知のキーのデフォルト値としてゼロを使用するテーブルを作成します。次に、キーが「there」と「here」で、値が1と2の2つの項目をテーブルに追加します。
セットもリストに似ていますが、特定の値のメンバーは 1 つしか含まれません。Icon には、++2 つのセットの和集合、**積集合、--差集合を生成する機能が含まれています。Icon には、さまざまな文字を含むセットである、定義済みの「Cset」が多数含まれています。Icon には&ucase、、、、、の4 つの標準 Cset があります。新しい Cset は&lcase、文字列を単一引用符で囲むことによって作成できます。たとえば、。&letters&digitsvowel := 'aeiou'
Iconでは、文字列は文字のリストです。リストであるため、ジェネレーターとして機能し、したがって、bang構文を使用して反復処理できます。
文字列の各文字を別々の行に出力します。
文字列から部分文字列を抽出するには、括弧で囲んだ範囲指定を使用します。範囲指定は、単一の文字へのポインタ、または文字列のスライスを返すことができます。文字列は右または左からインデックス指定できます。文字列内の位置は、文字1 A 2 B 3 C 4の間に定義され、右から−3 A −2 B −1 C 0のように指定できます。
例えば、
最後の例では、終了位置の代わりに長さを使用していることが示されています。
添え字指定は、式内の左辺値として使用できます。これを使用して、文字列を別の文字列に挿入したり、文字列の一部を削除したりできます。例:
文字列処理をさらに簡略化する方法として、で呼び出されるスキャン?システムがあり、これは文字列に対して関数を呼び出します。
Icon は、文字列の左側を対象文字列?として参照し、それを文字列関数に渡します。 は、検索テキストをパラメータ 1 として、検索対象の文字列をパラメータ 2 として、2 番目のパラメータを受け取ります。2番目のパラメータの使用は暗黙的であり、プログラマが指定する必要はありません。単一の文字列に対して複数の関数が連続して呼び出される一般的なケースでは、このスタイルにより、結果として得られるコードの長さを大幅に短縮し、可読性を向上させることができます。Icon 関数のシグネチャは、定義内で対象文字列パラメータを識別するため、この方法でパラメータを巻き上げることができます。find?
これ?は単なる構文糖衣ではなく、後続の文字列操作のための「文字列スキャン環境」も設定します。これは、2つの内部変数とに基づいています。&subjectは&pos元&subjectの文字列へのポインタであり、&posは文字列内の現在の位置、つまりカーソルです。Iconのさまざまな文字列操作手順は、これらの2つの変数を使用するため、プログラマが明示的に指定する必要はありません。例:
生成されるもの:
subject=[これは文字列です], pos=[1] 組み込み関数とユーザー定義関数を使用して、スキャン対象の文字列内を移動できます。組み込み関数はすべてデフォルトで と に設定されており、&subjectスキャン&pos構文を使用できます。次のコードは、文字列内の空白で区切られたすべての「単語」を書き込みます。
この例では、いくつかの新しい関数が導入されています。posは の現在の値を返します&pos。 の値をそのまま使用するのではなく、この関数が必要な理由はすぐには明らかではないかもしれません&pos。その理由は、は変数であるため、プロシージャが持つことができる&pos値 を取ることができないからです。 したがって、は の軽量ラッパーを提供し、に対して手書きのブール値テストを用意することなく、 Icon の目標指向フロー制御を簡単に使用できるようにします。 この場合、テストは「is &pos zero」であり、Icon の文字列位置の奇数番号付けでは、これは行末です。 がゼロでない場合、はを返し、 は で反転され、ループが続行されます。&failpospos&pos&pospos&failnot
many現在の位置から、指定された Cset パラメータの 1 つ以上の例を検索します&pos。この場合、スペース文字を探しているので、この関数の結果は、 の後の最初の非スペース文字の位置になります&pos。はその位置にtab移動しますが、たとえば が文字列の末尾からはみ出した場合など、&posが再び発生する可能性があります。は基本的に の逆です。指定された Cset の直前の位置を返し、例ではそれを別の で に設定します。 は、行末で停止するためにも使用されます。&failmanyuptomany&postab
この例は、ピリオド、コンマ、その他の句読点、タブや改行なしスペースなどの他の空白文字を含む、より適切な「単語分割」Csetを使用することで、より堅牢にすることができます。そのCsetは、およびで使用できmanyますupto。
より複雑な例では、ジェネレーターと文字列スキャンが言語内に統合されている様子を示します。
ローレンス・トラットはIconに関する論文を執筆し、その実世界での応用例を検証し、いくつかの懸念事項を指摘した。その中には、文字列処理に由来するものの、他の分野ではあまり意味をなさない多くの実用的な決定事項が含まれていた。[ 24 ]その中には、次のようなものがある。
手続きの最後にデフォルトで失敗するという決定は、ジェネレータの文脈では理にかなっていますが、一般的な手続きの場合はそうではありません。上記の例に戻ると、write(f(-1))期待どおりに出力されません。ただし: [ 24 ]
結果として 10 が出力されます。この種の問題は全く明らかではなく、対話型デバッガでもすべてのコードが呼び出されますが、x期待される値を取得しません。これは、プログラマがどの言語でも注意しなければならない「落とし穴」の 1 つとして片付けられるかもしれませんが、Tratt はさまざまな Icon プログラムを調べ、プロシージャの大部分がジェネレータではないことを発見しました。これは、Icon のデフォルトの動作はごく少数の構造でのみ使用されているにもかかわらず、他のすべての構造で潜在的なエラーの主要な原因となっていることを意味します。[ 24 ]
もう1つの問題は、ブールデータ型[ c ]と従来のブール論理がないことです。成功/失敗システムは、最終的な目標が値をチェックすることであるほとんどの場合に機能しますが、これは一見単純なコードでも奇妙な動作につながる可能性があります。[ 25 ]
このプログラムは「taken」と出力します。その理由は、テスト がc値を返すためです。その値は&null、初期化されていないすべての変数のデフォルト値です。[ 26 ]&nullは有効な値なので、if c成功します。これをテストするには、テストを明示的にする必要がありますc === &null(または、より慣用的な Icon 式if /c then ...)。Tratt は、テストが「c がゼロかどうか」または「c が存在するかどうか」をテストしていると誤って想定したため、自己文書化コード を損なうと考えました。[ 25 ]