那几乎是Lisp!


14

挑战

您的挑战是为一种类似Lisp的语言设计一个解释器,此后将被创造出来:GLispGLisp的程序代码将包含任意数量的由方括号表示的嵌套表达式,格式如下:

(func arg1 arg2 ...)

注意,解释器必须在方括号,函数和参数之前和之后允许多余的空格字符。

种类

您将实现四种类型,整数,列表,布尔值和函数。可以使用自己的语法将整数和布尔值显式插入源代码中。您的解释器必须假设一系列数字字符表示一个整数(您不必实现显式插入负整数的语法)。您的解释器还必须假定truefalse被指定为布尔值。用户无法明确定义函数,它们将始终返回单个值(任何长度的列表都计为单个值)。

功能

需要实现以下功能,格式为Function,Arity。如果Arity n以加号开头,则表示一个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,则必须返回逻辑逻辑上的任意参数序列
    • (- 8 4 3) -> 1
    • (- 0 123) -> -123
    • (- true false false true false) -> true
  • *,2+

    • 如果所有参数均为Integer类型,则必须返回参数的乘积
    • 如果一个参数的类型为List,而另一个参数的类型为Integer(您可以假定这些仅是给定的唯一参数),则必须重复返回包含项的新Listarg1arg2
    • (* 1 2 3 4 5) -> 120
    • (* (list 1 2 3) 2) -> (list 1 2 3 1 2 3)
  • /,2+

    • 如果所有参数均为Integer类型,则必须返回参数(arg/arg2/ ...)的商(您可以假定除法是顺序进行的,并且每一步的小数部分都将被截断)
    • 如果一个参数的类型为List,另一个参数的类型为Function,则必须在映射到每个值之后返回结果Listarg2
    • (/ 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

    • 如果参数为整数类型,则必须返回以1递增的Integer
    • 如果参数的类型为List,则必须将List沿顺时针方向旋转一圈后返回
    • (inc 1) -> 2
    • (inc (list 1 2 3)) -> (list 3 1 2)
  • 十二月 1

    • 如果参数为Integer类型,则必须返回减1 的Integer
    • 如果参数为List类型,则必须将逆时针旋转的List返回一圈
    • (dec 1) -> 0
    • (dec (list 1 2 3)) -> (list 2 3 1)
  • 如果,3

    • 如果给定三个任意类型的参数:如果arg1true为true,则返回arg2,否则返回arg3
    • (if (not (list 1)) 8 false) -> false
  • 不是 1

    • 如果给定任何类型的参数,则如果true arg1为False,则返回true,否则返回false
    • (not (list)) -> true
  • 1

    • 如果给出类型为List的参数,则返回的长度arg1
    • (len (list 4 2 true (list 3) (list))) -> 5

真值表: 0, (list), false -> false,其中(list)表示空列表。其他一切都是true

您的解释器可以是从stdin或文件中读取源输入的完整程序,也可以是将源作为字符串并返回输出值的函数。

如果选择前者,输出为整数是简单的数字,用于布尔truefalse,和用于列表是一个空格分隔包含在括号(例如值的序列(1 2 3 4 (5 6 7))表示(list 1 2 3 4 (list 5 6 7)))。

如果选择后者,则必须以实现语言的相应类型返回该值,或者如果不存在类似类型,则返回一个自定义类型。如果语言没有列表类型,则列表可以作为数组或向量返回;布尔应以该语言的布尔类型返回;如果语言不支持布尔型,则返回自定义类型。

测试用例

(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
globby

1
我们应该如何评价(+ 3 (if false 5))?一般来说,什么都不是?您未指定要重调的任何单元类型
骄傲的haskeller 2015年

3
1.为什么(+ bool bool...)逻辑与和(- bool bool...)逻辑或?标准的环符号将+用于OR和*AND。2.“无效输入”是否旨在涵盖(/ 2 0)语法上正确的情况?3.对于=,如果值不完全相同,是否应该返回false?4.的定义not似乎是倒退的。5.什么是代币?您说的是解释器必须处理额外的空格,但您没有说它可以依靠什么空格。对于类似这样的复杂问题,您确实应该使用沙盒,以便可以检查规格。
彼得·泰勒

1
尚不清楚部分应用程序应如何工作:((+ 2 3) 4)等于9还是错误?值得注意的是,对于var-arg函数,尚不清楚何时应考虑将应用程序局部化。它变得更加混乱((if true (+ 2 3) (- 5)) 4)
MtnViewMark 2015年

Answers:


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另一个提示:您可以s=string使用和使用它,而不要同时使用stringchars"C"vs.char 'C' .)。另一个提示:使用警卫代替ifs
骄傲的haskeller 2015年

我想到的另一件事:您可以Maybe通过列表对值进行编码。Nothing[]并且Just x[x]。这摆脱了冗长的构造函数,并添加了更多功能:if p then Just x else Nothingis [x|p](==Nothing)isnull,list monad可能与maymon相同,依此类推。
2015年

@proudhaskeller谢谢,全部适用!
MtnViewMark 2015年

4

蟒蛇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
Def

3

通用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
只要它不是一种评估函数……
Def

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

一个很hacky的解决方案。它将所有内容存储为可输出格式的字符串-它们的类型可以通过首字母区分- 0..9对于数字,(用于列表tf布尔值,以及函数的其他所有内容。

运行使用该r功能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.