プログラミング言語J.アマチュアを見てください。 パート4.ボックスとサイクル。 おわりに

プログラミング言語の前の記事J.アマチュアの外観。 パート3.配列



1.ボックス





Jの名詞は配列であるという事実に既に直面しています。 単一の定数値でも、ベクトル演算は許可されます。 一緒に、これらすべてが便利なベクトル同種プログラミング環境を構成します。



ただし、配列には独自の制限があることは明らかです。 Jでは、デフォルトでは長方形の配列しか存在しないため、いわゆる ギザギザの配列。 また、配列は、異なる要素で構成されるリストには適していません。





これらの問題を解決するために、Jは異種シーケンス-ボックスを作成および使用するためのツールを提供します。 ボックスは、任意の要素を格納できる一種のコンテナです。 したがって、ボックスの配列は、タイプ(void *)の要素の一種の配列です。 したがって、たとえば、ボックス化されたシーケンスの最初の要素は1次元配列、2番目は数値、3番目は整数の行列です。



ボックスを作成するには、モナドの動詞「<」を呼び出して、ボックスから要素を抽出(「開く」)する必要があります-モナドの動詞「>」:



]x =. <1 2 3 +-----+ |1 2 3| +-----+
      
      







ボックス自体はASCIIグラフィックスで描画されます。 次に、ボックスの値を抽出します。



  >x 1 2 3
      
      







ボックスにいくつかの要素を追加するために、要素を一連のボックスに接続する動詞「;」が意図されています。



  1;2;2 +-+-+-+ |1|2|2| +-+-+-+ (i.10) ; 42 ; (i. 2 3) +-------------------+--+-----+ |0 1 2 3 4 5 6 7 8 9|42|0 1 2| | | |3 4 5| +-------------------+--+-----+
      
      







このようなボックス化されたシーケンスの要素をリストするには、既知の品詞を使用できます。 たとえば、副詞「の間に」:



  ;/ i.3 +-+-+-+ |0|1|2| +-+-+-+
      
      







または動詞の構成:



  (#@>)"0 (1 2 3; 2; 3 4) NB.     ( = 0)    3 1 2
      
      







次に、動詞「{」を使用して、ボックスの2番目の要素を抽出します。



  1 { ;/i.3 +-+ |1| +-+
      
      







この例では、次の瞬間に注意を払う必要があります。インデックス呼び出しは、配列のボックス化された要素を自動的にアンパックせずに返します。



前の式から、特定の動詞をボックスの各要素に適用する場合、その動詞がボックス名詞にラップされたオペランドを取るたびに結論付けることができます。 各呼び出しで配列から要素を「引き出し」、結果をボックスに「移動」するアクションの後に、既知のユニオン「&。」を使用できます。



ユニオン&。は、右動詞をオペランドに適用し、左動詞を結果に適用します。 次に、正しい動詞と逆の動詞が結果に適用されます。 したがって、上記の段落で説明したアルゴリズムを実際に繰り返しました。 このスキームを使用して、ボックスの各要素を2倍にします。



  (+: &. >) ;/ i.3 +-+-+-+ |0|2|4| +-+-+-+
      
      







式&。>は非常に頻繁に使用されるため、デフォルトでは各シンボルに関連付けられています。



  each &.> (+: each) ;/ i.3 +-+-+-+ |0|2|4| +-+-+-+
      
      







データ処理速度では、ボックスが大幅に(最大3桁!)数値配列に遅れていることに注意してください。



2.複数行動詞の定義





「エレガントなプログラミング言語を作成するには何が必要ですか?」

アイバーソン:「秘密はあなたが彼に期待することをすることです。」

フレッドブルックス、ケネスアイバーソンのお祝い、2004-11-30




動詞を暗黙の形式で提示することは常に可能とは限りません。 このために、Jには特別な構造があり、これを命令型と呼びます。 まず、これらは「3:」および「4:」という操作です(定数動詞「3:」および「4:」と混同しないでください)。 デフォルトのオペランドは「y」、左側は「x」です。 例:



  v1 =: 3 : '- y' NB.  v2 =: 4 : 'x + y' NB. 
      
      







命令的な定義をタクティックな形式で記述できると感じているが、方法がわからない場合は、すばらしい標準動詞変換を使用できます。



  13 : 'x + y' + 13 : 'x - (y + 1)' [ - 1 + ]
      
      







複数行の動詞を作成するには、同様の構成が使用されます。 さらに、ほとんどの関数型言語と同様に、最後に計算された値が返されるため、returnステートメントの類似物は必要ありません。 複数行の動詞では、ローカル変数も使用できます。「=。」操作を使用して決定されます。 動詞の定義を終了するための記号は、記号「)」です。



  v =: 4 : 0 NB.  z =. y + 1 NB.  "z =: ..."     z x - z ) NB.  ,    . 3 4 v 1 2 1 1
      
      







Jには、条件(.if)、ループ(.while)などをチェックするための特別な構造もあります。 詳細については、ドキュメントを参照することをお勧めします。



3.再帰





再帰的クイックソート機能は、導入部で説明しました。 別の例を見てみましょう。 Pythonには、そのような関数が組み込まれていないかのようにシーケンスの長さを決定するための簡単な関数を記述します。



 def len(xs): """>>> len([1,2,3]) 3""" if xs == []: return 0 return 1+len(xs[1:])
      
      







Jのベクトルの長さを計算するための再帰関数を作成するには、追加の述語動詞を導入して、名詞が少なくとも1つの要素を持つシーケンスであるかどうかを判断する必要があります。 「is array」というフレーズからこの述語isaを呼び出します。 最初に、この動詞の使用例を示します。



  isa 1 NB.  0 isa i.0 NB.  0 isa 1 2 3 NB.  3
      
      







特定の位置でベクトルから要素を抽出する動詞を通じて、オペランドが1を超える長さのベクトルであるかどうかを判断します。 これは動詞「{」です



  isa =: ((1: 1&{) :: 0:) : [:
      
      







したがって、式「1&{」が正しく満たされる場合、オペランドは長さが1より大きい配列であると見なされます。そうでない場合はfalse(ゼロ)を返します。 また、動詞の二項呼び出しの禁止を定義に追加しました。



条件チェックをシミュレートするために、@。Unionを使用し、右側のオペランドによって決定される、その位置で動詞をボックスから呼び出します。 つまり



  3:`4: @. 1 4: 3:`4: @. 0 3:
      
      







右のオペランドがlength = 1のベクトルである場合、length = 1を返す必要があります。 この名詞の述語isaが0を返す場合。



  len =: 1:`(.....) @. isa
      
      







省略記号の代わりに、再帰呼び出しを実装して、送信されたシーケンスのテールの長さを計算する必要があります。 Jの再帰呼び出しが動詞「$:」によって実装されるという事実を利用します。 T.O. 私たちは得る



  len =: 1:`(>:@$:@}.) @. isa len 1 2 3 3 len 17 1
      
      







次のステップは、再帰呼び出しが末尾になるように動詞を書き換えることです。 これを行うには、左のオペランドに累積値を格納します。したがって、動詞は二項になります。



  len2 =: [`((>:@[) $: (}.@])) @. (isa@]) 1 len2 i.7 7
      
      







動詞の定義は食欲をそそらないように見えますが、実際はそうです。 Pythonの例を使用して、動詞len2のアルゴリズムを説明します。



 def len2(acc,xs): if xs == []: return acc else: return len2(acc+1, xs[1:])
      
      







書いたコードの速度を比較することは興味深いです。 これを行うには、動詞「6 !: 2」を使用します。これは、左オペランドに示されている回数だけ右オペランドを実行し、各実行の平均実行時間を秒単位で返します。



  time =: 6!:2 x =: i.1000 10 time 'len x' NB.   0.00614873 10 time '1 len2 x' NB.     0.00553225 10 time '# x' NB.      1.67641e_6
      
      







ご覧のとおり、この場合、組み込みのJツールの使用は、独立した実装よりも3桁高速です。 さらに、Jには再帰の深さに制限があり、末尾再帰の最適化はありません。



このような再帰的表現の使用は、トレーニングおよび緊急の場合にのみ推奨されることに注意してください。



4.名前空間





Jでのプログラミングへのオブジェクト指向アプローチの使用については説明しません。 興味がある人のために、JでOOPのサポートがあるとしましょう。 詳細については、例えばLearning Jをご覧ください。



ただし、Jには、OOPツールキットに似た構文を持つ名前空間を使用するための特別な構成体があることに注意してください。



新しい名前空間の始まりは、式で始まる必要があります。



  cocurrent 'name'
      
      







引用符で囲まれた名前空間名を記述する必要がありますが、これが現在の名前になります。 デフォルトの名前空間は ' base



'です。 したがって、名前空間のコードブロックが終了したらすぐに、式を使用してデフォルトのスコープに戻る必要があります。



  cocurrent 'base'
      
      







カプセル化された名前空間のメンバーにアクセスする場合、各要素に_name_という接尾辞を追加する必要があります。「name」は名前空間の名前です。 大文字の名前空間が推奨されます。 これが良い例です:

  cocurrent 'INNER' rate =: 10 v =: 3 : 'rate + y' cocurrent 'base' v_INNER_ 1 11 rate_INNER_ =: 1 v_INNER_ 1 2
      
      







5.例





セクションの最後に、1つの教科書の例-クイックソート動詞を示します。 JのHoarソートは次のように記述できます。



  sel=: 1 : 'x # [' quicksort=: 3 : 0 if. 1 >: #y do. y else. (quicksort y <sel e),(y =sel e),quicksort y >sel e=.y{~?#y end. )
      
      







行ごとに定義を分析してみましょう。





前に示したように、クイックソートは1行で記述できます。



  quicksort=: (($:@(<#[) , (=#[) , $:@(>#[)) ({~ ?@#)) ^: (1<#)
      
      







「$:」は動詞の再帰呼び出しを意味し、「@」という表現は動詞の逐次計算を定義することを思い出してください。



6.ヒント



記事を書く秘secretをよく知りたいですか? 500件の記事を作成します。

ロジャー・ホイ、ケン・アイバーソンを思い出す、2004






ここで、Jの第一人者プログラマーのコードは、上記の推奨事項のすべてに違反することが多いことに注意してください。





7.さらに読むこと



何が起こっているのかについて複数の説明を決して与えない-後者は常に正しい

ケネス・アイバーソン。




結論の代わりに





私はかつてケンに言った、「ケン、あなたは私のお気に入りのプログラミング言語のデザイナーであり、ドン・クナットは私のお気に入りのプログラマーです。」 ケンはすぐに尋ねました:「私のプログラミングの何が問題なのですか?」

-ジョーイタトル、ケネスアイバーソンのお祝い、2004-11-30







All Articles