それはほとんどLispです!


14

チャレンジ

あなたの課題は、Lispに似た言語用のインタープリターを設計することですGLispのプログラムコードは、次の形式の括弧で示された任意の量のネストされた式で構成されます。

(func arg1 arg2 ...)

インタプリタは、括弧、関数、および引数の前後に余分な空白文字を許可する必要があることに注意してください。

タイプ

整数、リスト、ブール、関数の4つのタイプを実装します。整数とブール値は、独自の構文を使用してソースコードに明示的に挿入できます。インタープリターは、一連の数字が整数を示すと想定する必要があります(負の整数を明示的に挿入する構文を実装する必要はありません)。また、インタープリターはtruefalseブール値が指定されていると想定する必要があります。関数はユーザーが明示的に定義することはできず、常に単一の値(任意の長さのリストが単一の値としてカウントされます)を返します。

関数

以下の関数は実装する必要があり、形式は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
  • *、2 +

    • すべての引数がInteger型の場合、引数の積を返す必要があります
    • 一方の引数がリスト型で、もう一方の引数が整数型である場合(これらが唯一の引数であると仮定することができます)、アイテムを繰り返し使用して新しいリストを返す必要があります。arg1arg2
    • (* 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)
  • 、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つの真理値が場合:任意の型の引数をarg1trueで、リターンarg2、それ以外のリターンarg3
    • (if (not (list 1)) 8 false) -> false
  • ない、1

    • 任意の型の引数が与えられ、真理値arg1がFalseの場合、return true、そうでない場合はreturn false
    • (not (list)) -> true
  • len、1

    • List型の引数が指定された場合、arg1
    • (len (list 4 2 true (list 3) (list))) -> 5

真理値表: 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

これはコードゴルフなので、バイト数が最も少ないインタープリターが勝ちます!


どのように解釈し(if (not (array 1)) 8 false) -> falseますか?
-feersum

@feersumの良いキャッチは、8になるはずです
。-グロビー

1
どのように評価すべき(+ 3 (if false 5))ですか?一般的に言えば、実際に「何も返さない」とは何ですか?再調整するユニットタイプを指定しませんでした
誇りに思ってhaskeller

3
1.なぜ(+ bool bool...)論理ANDと(- bool bool...)論理ORですか?標準のリング表記は+、ORおよび*ANDに使用されます。2.「無効な入力」(/ 2 0)は、構文的に正しいケースなどを対象としていますか?3.の=場合、値がすべて同じではない場合、戻りfalseますか?4.の定義はnot後方に見える。5.トークンとは何ですか?インタプリタは余分な空白を処理する必要があると言いますが、どの空白に依存できるかは言いません。このような複雑な質問には、仕様を確認できるようにサンドボックスを実際に使用する必要があります。
ピーターテイラー

1
部分的なアプリケーションがどのように機能するかは明確ではありません:((+ 2 3) 4)等しい9かエラーですか?特に、var-arg関数の場合、アプリケーションを部分的に考慮する必要があるかどうかは明確ではありません。((if true (+ 2 3) (- 5)) 4)
MtnViewMark

回答:


6

Haskell、1370 1263 1179 1128 1163 1107 1084バイト* 0.8 * 0.85 = 737.12

import Text.Parsec
data V=I Int|L[V]|T|F|P[V]|X|A|S|M|D|U|E|Q|J|K|C|N|W deriving Eq
m Q=0;m C=3;m f|f`elem`[J,K,N,W]=1;m _=2
l=length
x v=[n|I n<-v]
y v=[l|L l<-v]
z v=[0<1|T<-v]++[1<0|F<-v]
(&)f=l.f>>=(.l).(==)
b a|a=T|0<1=F
s(I n)=show n
s(L v)='(':tail(v>>=(' ':).s)++")"
s T=d!!0;s F=d!!1;s _="error"
i(L v)=e$i%v
i v=v
e(P v:a)=e$v++a
e(f:a)|m f>l a=P(f:a)
e(A:a)|x&a=I$sum$x a|y&a=L$concat$y a|z&a=b$and$z a
e(S:a)|x&a=I$f$x a|z&a=b$or$z a
e(M:a)|x&a=I$product$x a
e[M,v,I n]=e$A:replicate n v
e(D:a)|x&a=I$v$x a
e[D,L v,f]=L$map(\a->e[f,a])v
e[U,I a,I b]=I$a`mod`b
e(E:a:v)=b$all(==a)v
e(Q:a)=L a
e[J,I a]=I$a+1
e[J,L[]]=L[]
e[J,L v]=L$last v:init v
e[K,I a]=I$a-1
e[K,L v]=L$drop 1 v++take 1 v
e[C,a,b,c]|a`elem`[I 0,L[],F]=c|0<1=b
e[N,a]=e[C,a,F,T]
e[W,L v]=I$l v
e _=X
f(a:b)=a-sum b
v(a:b)=foldl div a b
(%)f=fmap f
p=k$choice$try%([(I .read)%many1 digit,L%between(w"(")(k$w")")(many$try p)]++zipWith((.return).(>>).w)d[T,F,A,S,M,D,U,E,Q,J,K,C,N,W])
k=(spaces>>)
w=string
d=words"true false + - * / % = list inc dec if not len"
g=either show(s.i).parse p""
main=interact g

完全なプログラム、読み取りstdinおよび書き込みstdoutg関数のバージョンも同様です。

部分関数と遅延評価の両方を実装します ifます。

(関数バージョンの)サンプル実行:

λ: g "(list 1 2 3 (list 4 5 true))"
(1 2 3 (4 5 true))

λ: g "(/ 4000 (+ 1 2 3 4 (* 5 8)))"
80

λ: g "(+ (not (- (len (list 5 6 7)) (/ 10 3))) true)"
true

λ: g "(if (           len (list )  ) 4 (if    (+ (= 8 8    8) (not (list 4))) 8 5))"
5

λ: g "(if false (/ 1 0) 5)"
5

λ: g "((+ 2) 3)"
5

λ: g "(/ (list 1 2 3) (+ 2))"
(3 4 5)

これで、説明のすべてのユニットテストがあります。

λ: runTests 
passed: g "(+ 1 2 3 4 5)" ==> 15
passed: g "(+ (list 1 2) (list 3 4))" ==> (1 2 3 4)
passed: g "(+ true true true)" ==> true
passed: g "(- 8 4 3)" ==> 1
passed: g "(- 0 123)" ==> -123
passed: g "(- true false false true false)" ==> true
passed: g "(* 1 2 3 4 5)" ==> 120
passed: g "(* (list 1 2 3) 2)" ==> (1 2 3 1 2 3)
passed: g "(/ 100 10 3)" ==> 3
passed: g "(/ (list 1 2 3) inc)" ==> (2 3 4)
passed: g "(% 4 2)" ==> 0
passed: g "(= 0 0 0)" ==> true
passed: g "(= 0 false (list))" ==> false
passed: g "(list 3 4 (list 5))" ==> (3 4 (5))
passed: g "(inc 1)" ==> 2
passed: g "(inc (list 1 2 3))" ==> (3 1 2)
passed: g "(dec 1)" ==> 0
passed: g "(dec (list 1 2 3))" ==> (2 3 1)
passed: g "(if (not (list 1)) 8 9)" ==> 9
passed: g "(not (list))" ==> true
passed: g "(len (list 4 2 true (list 3) (list)))" ==> 5
passed: g "(list 1 2 3 (list 4 5 true))" ==> (1 2 3 (4 5 true))
passed: g "(/ 4000 (+ 1 2 3 4 (* 5 8)))" ==> 80
passed: g "(+ (not (- (len (list 5 6 7)) (/ 10 3))) true)" ==> true
passed: g "(if (           len (list )  ) 4 (if    (+ (= 8 8    8) (not (list 4))) 8 5))" ==> 5
passed: g "(if false (/ 1 0) 5)" ==> 5
passed: g "((+ 2) 3)" ==> 5
passed: g "(/ (list 1 2 3) (+ 2))" ==> (3 4 5)

Bの場合 e[K,L _]、使用することができdrop 1 、安全のバージョンとしてtail及び使用takeの安全なバージョンのためheadの二つの定義参加e[K,L _]
誇りhaskeller

関数notElem.another tip s=stringを使用できます。両方stringchars"C"vs. char 'C')の代わりに使用できます。別のヒント:ifsの代わりにガードを使用してください
誇りに思ってhaskeller

私が考えたもう一つのこと:Maybeリストによって値をエンコードすることができます。Nothingであり[]Just xです[x]。これは長いコンストラクタを取り除き、さらにいくつかの機能を追加します:if p then Just x else Nothingis [x|p](==Nothing)is null、リストモナドは多分モナドなどと同じになります。
誇りに思ってhaskeller

@proudhaskellerありがとう、すべて適用されました!
MtnViewMark

4

Python 2、1417 * 0.8 * 0.85 = 963.56

from operator import*
A=type;K="list"
def E():print"E";exit()
def R(G):
 len(G)or E();T=G.pop(0);L=[]
 if"("==T:
  G or E()
  while")"!=G[0]:L+=[R(G)];G or E()
  G.pop(0);return L
 if")"==T:E()
 try:
  x=eval(T.title())
  if Q(x)<2:return x
  E()
 except:return T
H="+ - * / = % if inc dec not len"
Z=lambda y:lambda x:reduce(y,x)
D=dict(zip(H.split(),[[sum,any,0,lambda x:sum((y[1:]for y in x),[K])],[Z(sub)],[Z(mul),all,0,lambda x:x[0][:1]+x[0][1:]*x[1]],[Z(div),lambda x:[K]+map(lambda z:S([x[1],z]if Q(x[1])==2else x[1]+[z]),x[0][1:])],[lambda x:len(set(map(str,x)))<2]*6,[lambda x:x[0]%x[1]],[lambda x:S(x[2])if S(x[0])in[0,[K]]else S(x[1])]*6,[lambda x:x[0]+1,0,0,lambda x:x[0][:1]+x[0][-1:]+x[0][1:-1]],[lambda x:x[0]-1,0,0,lambda x:x[0][:1]+x[0][2:]+[x[0][1]]],[lambda x:x[0]in[0,[K]]]*6,[0]*3+[lambda x:len(x)-1]]))
H=H[:15]+H+" if"
def Q(x):
 t=A(x);w=int,bool,str
 if t in w:return w.index(t)
 if t==list and x:return 5-(2*(x[0]==K)+(str==A(x[0])and len(x)<H.count(x[0])+1))
 E()
def S(G):
 if Q(G)<2:return G
 G or E();c=G[0];r=G[1:];c==K or r or E()
 if c!="if":r=[x if Q(x)in{2,4}else S(x)for x in r]
 if c==K:return[c]+r
 k=map(Q,r);m=min(k);M=max(k);v=[m,[-1,3][{m,M}=={4,5}]][m!=M]
 try:return D[c][v](r)
 except:E()
def C(x):return"(%s)"%" ".join(map(C,x))if A(x)==list else str(x).lower()
def I(G):
 for c in"+-*/%=()":G=G.replace(c," %s "%c)
 return C(S(R(G.strip().split())))
print I(raw_input())

完全なオーバーホール。以前のバージョンを表示する場合は、編集履歴をご覧ください。

ゴルフをすることはもっとたくさんあります。ゆっくりと取り組んでいます。

zlib / base64では、1093 * 0.8 * 0.85 = 743.24を取得します。

import base64,zlib
exec zlib.decompress(base64.b64decode("eJx9VE1P4zAQvedXGEuV7MbttgX2kOADAtSugANbTljWKqSuNku+5Lg0BfHfd8ZJCwjt9tLpdN6bmTczXtuqIFVtbOIqS7KirqwbBufS7WoTX0uaZ42jwcqsyRXjUW2z0tErGps2c4x7/08251FAclOCARwQF9/L+biuajbh8Y1UOiDZmjIq5T0EkjnposDc/s5yQzk9knM10dFNKBXS6fhDzIHJGrexJbnxbNyz+Qhnd0jbSvOc5Ox+7DKXG8YRm63JHWv52SzqwS04Pci0qand3n0fLCQNyYgMyTciyQCBWZmSlUlJWTlsjgYPMk+Kx1VCdlFvtIBfbVLDdqLlwaVcZaljL1nNFuOmzlEhoVSzKURS7sREHFDgYmynppFeQ5s7SEVaCL3WXAv1wJrNY2cUm5yLJM8/YlsQSkVTHXoDKIatmmofvsqe+Xsg0IVFUrPe8RItmcJQ8aI7WcDmUs5M3hiCP0L1ornY02IFBy4cbmMcQ77GWeiWg6h6+P1DDAIHfS0H5xLSzDSHhGhNwCrVBDvVPu2yq+IrUTiFnv/Z9Qjq2/c/+pwQvaP/gmeAVR1Yf4EeyvMlTfTwOPysQssxISzXQi6A81SHi5DiQvpbwGWDXXTyHIx4K+FaxGNV5QJEw7UlDme93a/ddpyVK9Myx7s/pcRzI0m58qvlY05HbDb02kl5zUOUXyI9iomBXVFni3FabUrX+cMpbv9Vf6DL7kD90OcfbmEeHE4xTv0Bxha+QFv4Ka/xL3s4Q0CnR5JCo5GVqt1fVla+zsTJ236YHPe5xR6t7jBA1OdTqQ5BhCeJS3QnLI8LWWQle+LxLfhaNJ6lKgSMVxxr9VqI2zcpX0/E6ZvWqjiSt7o79r7+S2BUz5rZ93Pet3yBc+jCKBs0nA4ooeM/FaTD7Be4wFAdTqnX3HcA2oJnnFdbY3umH5142FcKfdFwNPw2kIzTaA5vnDV1nsD9p4KSQUPoIIVa+vIu2JLBYzYGUngR+P5FgE/gn1Ggtsn2V1bWG3T/BUW+qRU="))

注:スコアが上がっているのを見ると、おそらくいくつかのバグを見つけたからです


コードゴルフよりもコードの挑戦のよりそれでも、4872 * 0.8 = 3897,6
デフ

3

Common Lisp、868バイト* 0.85 = 737.8

LispでLispを実装するのはごまかしですか?ここでも最適化することがたくさんあります。

(SETF (READTABLE-CASE *READTABLE*) :PRESERVE)(PRINC(LABELS((B(X)(FIND X'(true false)))(R(X)(IF X'true'false))(V(X)(MEMBER X'(0()false)))(A(&REST X)(R(NOTANY #'V X)))(O(&REST X)(R(NOTEVERY #'V X)))(E(X &KEY N)(IF(LISTP X)(ECASE(FIRST X)(+(APPLY(IF(EVERY'NUMBERP #1=(MAPCAR(IF N #'IDENTITY #'E)(CDR X)))'+(IF(EVERY'LISTP #1#)'APPEND #'A))#1#))(-(APPLY(IF(EVERY'NUMBERP #1#)'- #'O)#1#))(*(IF(LISTP #2=(CAR #1#))(LOOP FOR I TO(1-(CADR #1#))APPEND #2#)(APPLY'* #1#)))(/(IF(LISTP #2#)(LOOP FOR I IN #2#COLLECT(E `(,(CADR #1#),I):N T))(REDUCE'FLOOR #1#)))(%(APPLY'MOD #1#))(=(R(LOOP FOR I IN(CDR #1#)ALWAYS(EQUAL I #2#))))(list #1#)(inc(IF(LISTP #2#)(APPEND(LAST #2#)(BUTLAST #2#))(1+ #2#)))(dec(IF(LISTP #2#)(APPEND(CDR #2#)`(,(FIRST #2#)))(1- #2#)))(if(IF(V(E(CADR X)))(E(CADDDR X))(E(CADDR X))))(not(R(V #2#)))(len(LENGTH #2#)))X)))(OR(IGNORE-ERRORS(OR(E(READ))"()")):E))

入力にエラーがある場合にEを出力します。サンプルの実行:

$ sbcl --script glisp.lisp
(list 1 2 3 (list 4 5 true))
(1 2 3 (4 5 true))

$ sbcl --script glisp.lisp
(/ 4000 (+ 1 2 3 4 (* 5 8)))
80

$ sbcl --script glisp.lisp
(+ (not (- (len (list 5 6 7)) (/ 10 3))) true)
true

$ sbcl --script glisp.lisp
(if (           len (list )  ) 4 (if    (+ (= 8 8    8) (not (list 4))) 8 5))
5

$ sbcl --script glisp.lisp
(this is an error)
E

$ sbcl --script glisp.lisp
(if (% 4 2) (this is an error) 42)
42

2
それはevalの機能のようなものではありません長いほど...
デフ

2

ハスケル、972

r=fst.f
f('(':s)|(f:a,b)<-g s=(f%filter(/="")a,b)
f s=span(`notElem`" ()")s
j=dropWhile(==' ')
g""=([],"")
g s|')':l<-r=([x],l)|(y,t)<-g$j r=(x:y,t)where(x,r)=f$j s
"%"%c=show$foldr(mod.read)(maxBound::Int)c
"+"%c|t(c!!0)<1="(list "++tail(c>>=(' ':).drop 6.init)++")"|t(c!!0)<2=show$sum$map read c|0<1=i$all((=='t').head)c
"-"%c|t(c!!0)<2=show$foldl1(-)$map read c|0<1=i$any((=='t').head)c
"*"%c=fst$f$"(+ "++unwords([1..read$last c]>>init c)++")"
"="%c=i$all(==c!!0)c
"/"%c|t(c!!0)<1,[a,b]<-c="list"%map(\x->b%[x])(fst$g$drop 6 a)|0<1=show$foldl1 div$map read c
"if"%[p,a,b]|elem p["0","()","false"]=b|0<1=a
"list"%c="(list "++unwords c++")"
"len"%[c]=show$length(words c)-1
"inc"%[c]|t c>0=show$read c+1|([],_)<-g$drop 6 c="(list)"|(x,_)<-g$drop 6 c="list"%(last x:init x)
"dec"%[c]|t c<1,(x,_)<-g$drop 6 c="list"%(drop 1 x++take 1 x)|0<1=show$read c-1
"not"%[c]="if"%[c,"false","true"]
s%c="?"
i p|p="true"|0<1="false"
t('(':_)=0
t(c:s)|c<':',c>'/'=1|elem c"th"=2
t _=3

非常にハッキーなソリューションです。これはすべてを出力可能な形式の文字列として保存します-それらのタイプは最初の文字で区別できます- 0..9数字、(リスト、tまたはfブール値のため、および機能については、他のすべて。

実行するには、r関数を使用します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.