チャレンジ
あなたの課題は、Lispに似た言語用のインタープリターを設計することです。GLispのプログラムコードは、次の形式の括弧で示された任意の量のネストされた式で構成されます。
(func arg1 arg2 ...)
インタプリタは、括弧、関数、および引数の前後に余分な空白文字を許可する必要があることに注意してください。
タイプ
整数、リスト、ブール、関数の4つのタイプを実装します。整数とブール値は、独自の構文を使用してソースコードに明示的に挿入できます。インタープリターは、一連の数字が整数を示すと想定する必要があります(負の整数を明示的に挿入する構文を実装する必要はありません)。また、インタープリターはtrue
、false
ブール値が指定されていると想定する必要があります。関数はユーザーが明示的に定義することはできず、常に単一の値(任意の長さのリストが単一の値としてカウントされます)を返します。
関数
以下の関数は実装する必要があり、形式はFunction、Arityです。Arityの前にn
プラス記号が付いている場合、それは1 n
つ以上の引数を示しています。特に指定されない限り、関数に与えられたすべての引数は同じ型であると仮定することができます。また、certian型に動作が指定されていない場合、その関数の引数はその型にはならないと想定することもできます。引数は、次の図のように参照されます。
(func argument1 argument2 ... argumentn)
+、2 +
- すべての引数がInteger型の場合、引数の合計を返す必要があります
- すべての引数がList型の場合、引数の連結を昇順(
arg1+arg2+ ...
)で返す必要があります - すべての引数のタイプがBooleanの場合、引数のすべての論理シーケンスを返す必要があります
(+ 1 2 3 4 5) -> 15
(+ (list 1 2) (list 3 4)) -> (list 1 2 3 4)
(+ true true true) -> true
-、2 +
- すべての引数がInteger型の場合、引数の差(
arg1-arg2- ...
)を返す必要があります - すべての引数がBoolean型の場合、引数のシーケンスの論理Anyを返す必要があります
(- 8 4 3) -> 1
(- 0 123) -> -123
(- true false false true false) -> true
- すべての引数がInteger型の場合、引数の差(
*、2 +
- すべての引数がInteger型の場合、引数の積を返す必要があります
- 一方の引数がリスト型で、もう一方の引数が整数型である場合(これらが唯一の引数であると仮定することができます)、アイテムを繰り返し使用して新しいリストを返す必要があります。
arg1
arg2
(* 1 2 3 4 5) -> 120
(* (list 1 2 3) 2) -> (list 1 2 3 1 2 3)
/、2 +
- すべての引数がInteger型の場合、引数の商(
arg/arg2/ ...
)を返す必要があります(除算は順次行われ、各ステップの小数部は切り捨てられると想定できます) - 一方の引数がList型で、もう一方の引数がFunction型の場合、すべての値にマッピングされた後、結果のListを返す必要があり
arg2
ます (/ 100 10 3) -> 3
(/ (list 1 2 3) inc) -> (list 2 3 4)
- すべての引数がInteger型の場合、引数の商(
%、2
- すべての引数がInteger型の場合、引数のモジュラスを返す必要があります
(% 4 2) -> 0
=、2 +
- 場合は、両方のすべての引数の型と値が同じである、あなたはtrueを返す必要があります。それ以外の場合は、falseを返します。
(= 0 0 0) -> true
(= 0 false (list)) -> false
リスト、0 +
- タイプに関係なく、すべての引数のリストを返す必要があります。引数が指定されていない場合、空のリストを返す必要があります
(list 3 4 (list 5)) -> (list 3 4 (list 5))
株式会社、1
- 引数がInteger型の場合、1ずつ増加したIntegerを返す必要があります
- 引数がList型の場合、Listを時計回りに1回転させて返す必要があります
(inc 1) -> 2
(inc (list 1 2 3)) -> (list 3 1 2)
12月、1
- 引数のタイプがIntegerの場合、1だけ減少したIntegerを返す必要があります
- 引数のタイプがListの場合、リストを反時計回りに1回転させて返す必要があります
(dec 1) -> 0
(dec (list 1 2 3)) -> (list 2 3 1)
の場合、3
- 与えられた場合は3つの真理値が場合:任意の型の引数を
arg1
trueで、リターンarg2
、それ以外のリターンarg3
(if (not (list 1)) 8 false) -> false
- 与えられた場合は3つの真理値が場合:任意の型の引数を
ない、1
- 任意の型の引数が与えられ、真理値
arg1
がFalseの場合、returntrue
、そうでない場合はreturnfalse
。 (not (list)) -> true
- 任意の型の引数が与えられ、真理値
len、1
- List型の引数が指定された場合、
arg1
(len (list 4 2 true (list 3) (list))) -> 5
- List型の引数が指定された場合、
真理値表:
0, (list), false -> false
、ここで(list)
空のリストを示します。それ以外はすべてですtrue
。
インタプリタは、stdinまたはファイルからソース入力を読み取る完全なプログラム、またはソースを文字列として受け取って出力値を返す関数のいずれかです。
前者を選択した場合、整数の出力は単なる数値であり、ブール型の出力はtrue
またはfalse
であり、リストの場合はスペースで区切られた括弧で囲まれた値のシーケンスです(例えばを(1 2 3 4 (5 6 7))
示します(list 1 2 3 4 (list 5 6 7))
)。
後者を選択する場合、値は実装言語の対応する型、または類似の型が存在しない場合はカスタム型で返される必要があります。リストは、言語が持っていない場合、配列またはベクトルとして返すことができるリストの種類を、ブール値は、言語のboolean型の、または言語は、それらをサポートしていない場合は、カスタム型として返されるべきです。
テストケース
(list 1 2 3 (list 4 5 true)) -> (1 2 3 (4 5 true))
(/ 4000 (+ 1 2 3 4 (* 5 8))) -> 80
(+ (not (- (len (list 5 6 7)) (/ 10 3))) true) -> true
(if ( len (list ) ) 4 (if (+ (= 8 8 8) (not (list 4))) 8 5)) -> 5
明確化
- インタプリタは、選択した方法で無効な入力を処理できますが、例外をスローしてはなりません(ただし、エラーメッセージを出力してスムーズに終了する場合があります)
- 関数は常に引数を左から右に評価します
- 無効な入力とは、構文的に正しくない入力です。これには、ブラケットの不一致、ゼロによる除算、および部分的に適用された関数が含まれますが、これらに限定されません(ボーナスを使用しない場合)
- の場合
=
、値のいずれかが異なるか、タイプのいずれかが異なる場合、false
ボーナス
- 部分的に適用された機能をサポートする場合は、スコア* 0.8。たとえば、
((+ 2) 3)
はと同じですが(+ 2 3)
、などを許可し(/ (list 1 2 3) (+ 2))
ます。引数の最小数よりも少ない関数を受け取った場合、関数は部分的に適用されていると想定できます if
返されない限り、適用された引数を評価しない場合は、スコア* 0.85
これはコードゴルフなので、バイト数が最も少ないインタープリターが勝ちます!
(+ 3 (if false 5))
ですか?一般的に言えば、実際に「何も返さない」とは何ですか?再調整するユニットタイプを指定しませんでした
(+ bool bool...)
論理ANDと(- bool bool...)
論理ORですか?標準のリング表記は+
、ORおよび*
ANDに使用されます。2.「無効な入力」(/ 2 0)
は、構文的に正しいケースなどを対象としていますか?3.の=
場合、値がすべて同じではない場合、戻りfalse
ますか?4.の定義はnot
後方に見える。5.トークンとは何ですか?インタプリタは余分な空白を処理する必要があると言いますが、どの空白に依存できるかは言いません。このような複雑な質問には、仕様を確認できるようにサンドボックスを実際に使用する必要があります。
((+ 2 3) 4)
等しい9
かエラーですか?特に、var-arg関数の場合、アプリケーションを部分的に考慮する必要があるかどうかは明確ではありません。((if true (+ 2 3) (- 5)) 4)
(if (not (array 1)) 8 false) -> false
ますか?