शिफ्ट इंटरप्रेटर लिखें


10

संपादित करें: जैसा कि आप में से कुछ को संदेह था, आधिकारिक दुभाषिया में एक बग था: रचना का क्रम .उलट गया था। मेरे पास दुभाषिया के दो संस्करण थे, और यहां गलत का इस्तेमाल किया। इस गलत संस्करण के लिए उदाहरण भी लिखे गए थे। मैंने रिपॉजिटरी में दुभाषिया, और नीचे दिए गए उदाहरणों को निर्धारित किया है। का वर्णन >भी थोड़ा अस्पष्ट था, इसलिए मैंने यह तय किया है। इसके अलावा, इतनी देर लगने के लिए माफी, मुझे कुछ वास्तविक जीवन के सामान में पकड़ा गया था।

EDIT2: मेरे दुभाषिया के कार्यान्वयन में एक बग .था , जो उदाहरणों में परिलक्षित हुआ (वे अपरिभाषित व्यवहार पर निर्भर थे)। मुद्दा अब तय हो गया है।

परिचय

Shift एक गूढ़ कार्यात्मक प्रोग्रामिंग भाषा है जिसे मैंने कुछ साल पहले बनाया था, लेकिन आज प्रकाशित किया गया है। यह स्टैक-आधारित है, लेकिन हास्केल की तरह स्वचालित करी भी है।

विशिष्टता

Shift में दो डेटाटिप्स हैं:

  • फ़ंक्शंस, जिनमें एक मनमाना पॉजिटिव एरिटी (इनपुट्स की संख्या) है, और जो आउटपुट की एक सूची लौटाते हैं। उदाहरण के लिए, एक ऐसा फ़ंक्शन जो अपने एकमात्र इनपुट को डुप्लिकेट करता है, उसमें arity 1 है, और एक फ़ंक्शन जो इसके दो इनपुट स्वैप करता है, में arity 2 है।
  • रिक्त स्थान, जो सभी समान हैं और कार्य नहीं होने के अलावा कोई अन्य उद्देश्य नहीं है।

Shift प्रोग्राम में शून्य या अधिक कमांड होते हैं , जिनमें से प्रत्येक एक ASCII वर्ण होता है। कुल 8 कमांड हैं:

  • !( लागू ) एक कार्य fऔर xस्टैक से एक मूल्य चबूतरे , और fकरने के लिए लागू होता है x। यदि f1 अंक है, तो सूची f(x)स्टैक के सामने जोड़ दी जाती है। यदि इसमें अरेटी है n > 1, तो एक नया- (n-1)वैरिएबल फ़ंक्शन gस्टैक पर धकेल दिया जाता है। यह इनपुट और रिटर्न लेता है ।x1,x2,...,xn-1f(x,x1,x2,...,xn-1)
  • ?( ब्लैंक ) स्टैक को एक खाली धक्का देता है।
  • +( क्लोन ) स्टैक के लिए एक यूनेरी फ़ंक्शन को धक्का देता है जो इसके इनपुट को डुप्लिकेट करता है: किसी भी मूल्य xको मैप किया जाता है [x,x]
  • >( शिफ्ट ) स्टैक को एक nअनियारी फंक्शन में धकेलता है जो एक- ऐरी फ़ंक्शन में लेता है f, और एक- (n+1)थ्री-फंक्शन gदेता है जो इसके पहले तर्क को अनदेखा करता है x, fशेष लोगों को कॉल करता है, और xपरिणाम के सामने tacks । उदाहरण के लिए, shift(clone)एक बाइनरी फ़ंक्शन है जो इनपुट a,bऔर रिटर्न लेता है [a,b,b]
  • /( कांटा ) स्टैक को एक टर्नरी फ़ंक्शन को धक्का देता है जो तीन इनपुट लेता है a,b,c, और रिटर्न [b]अगर aखाली है, और [c]अन्यथा।
  • $( कॉल ) ढेर करने के लिए धक्का एक द्विआधारी समारोह एक समारोह पॉप कि fऔर एक मूल्य xहै, और लागू होता है fके लिए xबिल्कुल के रूप में !करता है।
  • .( श्रृंखला ) ढेर करने के लिए एक द्विआधारी समारोह है कि पॉप दो कार्यों धक्का fऔर g, और उनकी संरचना देता है: एक समारोह hके रूप में ही arity है f, और जो अपने आदानों आम तौर पर लेता है, पर लागू होता है fउन्हें, और फिर पूरी तरह से लागू होता है gपरिणाम के लिए (कॉल इसके परिणाम के रूप में अप्रयुक्त आइटम के साथ अप्रयुक्त वस्तुओं के साथ यह कई बार fहै h। उदाहरण के लिए, मान लीजिए कि fएक द्विआधारी समारोह है कि अपने दूसरे तर्क क्लोन, और है gहै कॉल । यदि स्टैक में शामिल है [f,g,a,b,c]और हम करते हैं .!!, तो इसमें शामिल है [chain(f,g),a,b,c]; अगर हम !!आगे करते हैं , तो fपहले a,bउत्पादन के लिए लागू किया जाता है[a,b,b], तो gउस के पहले दो तत्वों पर लागू किया जाता है क्योंकि इसकी arity 2 है, उत्पादन [a(b),b], और स्टैक अंत में होगा [a(b),b,c]
  • @( कहते हैं ) एक अनियंत्रित फ़ंक्शन को धकेलता है जो केवल अपना इनपुट लौटाता है, और 0यदि यह रिक्त था, और 1यदि यह एक फ़ंक्शन था तो प्रिंट करता है।

ध्यान दें कि सभी कमांड !केवल स्टैक के लिए एक मूल्य को छोड़कर , इनपुट करने का कोई तरीका नहीं है, और किसी भी चीज़ को आउटपुट करने का एकमात्र तरीका उपयोग करना है @। एक कार्यक्रम एक-एक करके आदेशों का मूल्यांकन करके व्याख्या की है, मुद्रण 0या 1रों जब भी "कहते हैं कि" कहा जाता है, और बाहर निकलने। यहां वर्णित कोई भी व्यवहार नहीं है (रिक्त को लागू करना, लंबाई 0 या 1 के ढेर को लागू करना, रिक्त पर "चेन" कॉल करना) अपरिभाषित है: दुभाषिया दुर्घटनाग्रस्त हो सकता है, चुपचाप विफल हो सकता है, इनपुट के लिए पूछ सकता है, या जो भी हो।

काम

आपका कार्य Shift के लिए दुभाषिया लिखना है। इसे एसटीडीआईएन, कमांड लाइन, या फ़ंक्शन शिफ्ट प्रोग्राम की व्याख्या से लिया जाना चाहिए, और एसटीडीटी के लिए प्रिंट करें 0और 1एस और एस के परिणामी (संभवतः अनंत) आउटपुट को लौटाएं । यदि आप एक फ़ंक्शन लिखते हैं, तो आपको किसी तरह से अनंत-लंबाई वाले आउटपुट तक पहुंचने में सक्षम होना चाहिए (पायथन में जनरेटर, हास्केल में आलसी सूची, आदि)। वैकल्पिक रूप से, आप एक और इनपुट, एक संख्या ले सकते हैं n, और nआउटपुट के कम से कम अक्षरों को वापस कर सकते हैं यदि यह इससे अधिक लंबा है n

सबसे कम बाइट गिनती जीतता है, और मानक खामियों को रोक दिया जाता है।

परीक्षण के मामलों

यह Shift प्रोग्राम प्रिंट करता है 01:

?@!@@!

बाईं ओर से शुरू करें: एक रिक्त धक्का दें, धक्का कहें , फिर रिक्त स्थान पर कहें । यह आउटपुट 0। फिर, दो बार कहें पुश करें , और दूसरे कहने को पहले पर लागू करें । यह आउटपुट 1

यह कार्यक्रम हमेशा के लिए बंद हो जाता है, कोई उत्पादन नहीं:

$+.!!+!!

कॉल और क्लोन को पुश करें , फिर उन्हें चेन लागू करें (हमें दो !एस की आवश्यकता है क्योंकि चेन एक बाइनरी फ़ंक्शन है)। अब स्टैक में एक फ़ंक्शन होता है जो एक तर्क लेता है, इसे डुप्लिकेट करता है, और दूसरी पर पहली प्रति कहता है। इसके साथ +!!, हम इस फ़ंक्शन को डुप्लिकेट करते हैं और इसे स्वयं कहते हैं।

यह कार्यक्रम प्रिंट करता है 0010:

?@$.++>!.!!.!!.!!!!+?/!!!@!@>!!!

एक खाली धक्का और कहते हैं । फिर, एक द्विआधारी फ़ंक्शन की रचना करें जो इसके दूसरे तर्क की bप्रतिलिपि बनाता है, फिर पहले की प्रतिलिपि aबनाता है और खुद के साथ रचना करता है, फिर bलौटने पर रचना की प्रतिलिपि लागू करता है [a(a(b)),b]। इसे कहने के लिए लागू करें और रिक्त करें, फिर स्टैक पर शेष दो तत्वों पर कहें

यह कार्यक्रम प्रिंट करता है 0। प्रत्येक के लिए !!!जो आप इसे जोड़ते हैं, यह एक अतिरिक्त प्रिंट करता है 0

?@+$>!>!+>!///!!>!>!.!!.!!.!!+!!!!

एक खाली धक्का और कहते हैं । फिर, एक टर्नरी फ़ंक्शन की रचना करें जो f,g,xइनपुट और रिटर्न के रूप में लेता है [f,f,g,g(x)]। उस फ़ंक्शन को क्लोन करें, और इसे खुद पर लागू करें, कहें और रिक्त करें। यह एप्लिकेशन स्टैक नहीं बदलता है, इसलिए हम फ़ंक्शन को जितनी बार चाहें उतनी बार फिर से लागू कर सकते हैं।

यह कार्यक्रम अनंत अनुक्रम को मुद्रित करता है 001011011101111..., जहां एस की संख्या 1हमेशा एक से बढ़ जाती है:

@?/!@>!??/!!>!+.!!.!!.!!.+>!.!!$$$$+$>!>!$>!>!+>!$>!>!>!+>!>!///!!>!>!>!.!!.!!.!!.!!.!!.!!.!!.!!.!!.!!+!!!!!

रिपॉजिटरी में एक एनोटेट संस्करण होता है।


मैं यहाँ थोड़ा भ्रमित हूँ। जब आप लिखते हैं "लेता है" की तरह शिफ्ट कमांड में, क्या आपका मतलब पॉप है या क्या आप का अर्थ है लागू कमांड द्वारा लागू किया गया है?
tecywiz121

1
इसके अलावा, मैं वास्तव में आपकी कल्पना से निश्चित नहीं हूं कि श्रृंखला कैसे काम करने वाली है। क्या आप कृपया इसे एक उदाहरण से स्पष्ट कर सकते हैं?
tecywiz121

@ tecywiz121 यह है कि मैं इसे कैसे समझता हूं: कहते हैं कि स्टैक के शीर्ष पर आपको दो फ़ंक्शन मिले हैं, f(x1, x2, ..., xn)और g(y1, y2, ..., ym)। कॉलिंग .दोनों को पॉप करता है और एक फ़ंक्शन को धक्का देता है h(z1, z2, ..., zn)। अब आप उन सभी तर्कों को धीरे-धीरे करके इसे खा सकते हैं !। इस nतरह के अनुप्रयोगों के बाद , शेष फ़ंक्शन में केवल एक तर्क था, और उस बिंदु पर यह गणना करता है f(z1, z2, ..., zn)(यानी आपके द्वारा fकिए गए सभी तर्कों पर लागू होता है), जो कुछ नए मूल्यों को धक्का देता है, और फिर तुरंत mस्टैक से मूल्यों का उपभोग करता है और gउन पर कॉल करता है।
मार्टिन एंडर

@ मार्टिनबरनर अगर ज़गरब को लगता है कि यह नियमों के अनुरूप है तो आप आउटपुट के अधिकतम आकार को परिभाषित करने वाले दूसरे इनपुट पैरामीटर का उपयोग कर सकते हैं। यह आलसी मूल्यांकन मुद्दे का समाधान भी होगा।
रैंडम

@ tecywiz121 .बिल्कुल मार्टिन के बताए अनुसार काम करता है, सिवाय इसके कि यदि मूल्यों fसे कम की सूची लौटाता है m, तो परिणाम अपरिभाषित है (रचना में समानता है n, इसलिए यह स्टैक से अधिक तर्क नहीं खा सकता है)। अनिवार्य रूप से, के आउटपुट का fउपयोग एक अस्थायी स्टैक के रूप में किया जाता है, जिस पर उपयोग करके gधक्का दिया जाता है और लागू किया जाता mहै !, और उस के परिणाम को मुख्य स्टैक में जोड़ा जाता है।
जर्गर्ब

जवाबों:


12

पायथन 2, 752 667 534 506 445 436 427 404 398 393 बाइट्स

यह किसी भी तरह से कम नहीं है ... लेकिन मैंने अपना सर्वश्रेष्ठ प्रदर्शन किया। किसी भी गोल्फ सुझाव की बहुत सराहना की जाएगी ...

EDIT6: यह अब एक फंक्शन की बजाय एक स्क्रिप्ट है। इसे किसी फ़ाइल में सहेजें (shift.py, forex), इसके बाद इसे चलाएं $ python shift.py '<my_input>'। इनपुट को सिंगल कोट्स में डालना सुनिश्चित करें, या बैश इनपुट पात्रों के साथ पागल हो जाएगा।

EDIT7: Aaaaaaand ... यह अब पठनीय नहीं है। लेकिन मुझे 23 और बाइट्स से छुटकारा मिल गया, इसलिए यह अच्छा है, मुझे लगता है? मैं एक ungolfed संस्करण भी पोस्ट करूँगा।

EDIT8: एक और गोल्फ, @Zbb को धन्यवाद।

k,d=[],[]
u=k.append
def z(f,a=1):f.a=a;return f
exec "i=!x:x(*map(k.pop,[-1]*x.a)));e=dict(zip('?+>/$.@',[0,!x:u(x)<u(x)),!x:u(!a,*_:x(*_)<u(a),x.a+1))),!x,y,z:u((z,y)[x<1]),3),!x,y:u(!*_:x(y,*_),x.a-1))if x.a>1 else x(y),2),!x,y:u(!*_:x(*_)<i(y),x.a)),2),!x:d.append(`+(x>0)`)<u(x))]))".replace('!',"z(lambda ")
for _ in raw_input():
 try:[i,u][_ in e](e.get(_,e['$']))
 except:break
print d

संपादित करें: गोल्फ की मदद के लिए @DLosc को धन्यवाद! इसे 85 बाइट्स से कम करने का प्रबंधन किया।

EDIT2: अनावश्यक रैपरों का एक टन काट दिया, और इसे एक और 133 बाइट्स द्वारा गिरा दिया!

EDIT3: ... और चैट में @ Sp3000 और @orlp के लिए 28 और धन्यवाद!

EDIT4: @orlp & @ Sp3000 की मदद से, सभी डेकोरेटर को हटा दिया और अब यह 61 बाइट्स छोटा है।

EDIT5: मेरी मदद करो, मैं इसे रोक नहीं सकता .... 9 और बाइट चली गई। अंतिम प्रिंट स्टेटमेंट से छुटकारा पाने से एक और 7 की बचत होगी, लेकिन अगर आप एक लूप में मीटर () चलाते हैं, तो सभी आउटपुट एक ही लाइन पर हैं ... क्या यह ठीक है?

यहाँ एक ungolfed संस्करण है:

stack = []
push = stack.append

def arity(func,a=1): #give each of our functions an arity
    func.arity = a
    return func

def do(func): ##pop the args off the stack, then call the function
    args = map(stack.pop,[-1]*func.arity)
    func(*args)

def call(func,arg): #apply is just do(call)
    if func.arity == 1:
        func(arg)
    else:
        def curried(*a): #a quick little currier
            func(arg, *a)
        curried = arity(curried, func.arity - 1)
        push(curried)

def clone(arg):
    push(arg)
    push(arg)

def shift(func):
    def shifted(a, *arg):
        func(*arg)
        push(a)
    shifted = arity(shifted, func.arity + 1)
    push(shifted)

def fork(a, b, c):
    if a == 0:
        push(b)
    else:
        push(c)

def chain(func, gunc):
    def composition(*args):
        func(*args)
        do(gunc)
    composition = arity(composition, func.arity)
    push(composition)

def say(arg):
    print '10'[arg == 0],
    push(arg)

commands = {'?': 0,
            '+': arity(clone),
            '>': arity(shift),
            '/': arity(fork, 3),
            '$': arity(call, 2),
            '.': arity(chain, 2),
            '@': arity(say)}

def interpret(input_string):
    for command in input_string:
        try:
            if command == '!':
                do(call)
            else:
                push(commands[command])
        except RuntimeError: #this handles max recursion depth errors
            break            # for infinite programs
    print

if __name__ == "__main__":
    interpret(raw_input())

मूल विचार यह है कि अजगर सूची बहुत अच्छी तरह से एक स्टैक के रूप में काम करती है, और भंडारण के द्वारा u=k.append, न केवल मैं पात्रों को बचाता हूं, लेकिन मैं @uफ़ंक्शंस को आगे बढ़ाने के लिए एक सज्जाकार के रूप में भी उपयोग कर सकता हूं (अब नहीं!)।

चूँकि कुछ कार्य जो n-arity के कार्यों पर कार्य करते हैं, उन्हें मनमानी संख्या में तर्क स्वीकार करने में सक्षम होने की आवश्यकता है, मुझे इसका उपयोग करना था *args, जिसका मतलब था कि f.func_code.co_argcount पर नज़र रखने की मेरी मूल योजना को एक arity द्वारा प्रतिस्थापित किया जाना था डेकोरेटर विशेषता।

अनंत कार्यक्रमों को संभालने के संदर्भ में, दुभाषिया तब तक चलता है जब तक कि यह अधिकतम पुनरावर्ती गहराई तक नहीं पहुंचता; तल पर RuntimeError हैंडलर उस बिंदु पर चुपचाप बाहर निकल जाता है, और यह वर्तमान आउटपुट स्ट्रिंग को प्रिंट करता है।

परीक्षण के मामलों:

>>> tests
['?@!@@!', '$+.!!+!!', '?@$..!!+.!!+>!.!!!!+?/!!!@!@>!!!', '?@+$>!>!.!!+>!.!!///!!>!>!.!!+!!!!', '?@+$>!>!.!!+>!.!!///!!>!>!.!!+!!!!!!!', '?@+$>!>!.!!+>!.!!///!!>!>!.!!+!!!!!!!!!!', '?@+$>!>!.!!+>!.!!///!!>!>!.!!+!!!!!!!!!!!!!', '@?/!@>!.!!??/!!>!.!!+.!!.+>!.!!$$.!!$.!!$.!!+.!!$>!>!.!!$>!>!.!!+>!.!!$>!>!>!.!!+>!>!.!!///!!>!>!>!.!!+!!!!!']
>>> for t in tests: m(t)
0 1

0 0 1 0
0
0 0
0 0 0
0 0 0 0
0 0 1 0 1 1 0 1 1 1 0 1 1 1 1 0 1 1 1 1 1 0 1 1 1 1 1 1 0 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

1
मेरी पहली प्रतिक्रिया: @ _ @ गंभीरता से, हालांकि, अच्छा काम - स्टैक पर वास्तविक कार्य करना वास्तव में एक अच्छा समाधान है। कुछ सुझाव: 1) टर्नरी ऑपरेटरों को आमतौर पर एक तरह से या किसी अन्य को छोटा किया जा सकता है । 2) आप ['1','0'][...]बस के साथ बदल सकते हैं '10'[...]। 3) क्यों x is 0और क्यों नहीं x==0(या x<1)? 4) निर्दिष्ट करने के लिए परेशान मत करो RuntimeError, बस exceptकरेंगे। 5) चूंकि आप पायथन 2 का उपयोग कर रहे हैं, टैब और रिक्त स्थान अलग-अलग इंडेंटेशन स्तरों के रूप में गिने जाते हैं - लेकिन, आपको ~ 25 बाइट्स बचाना चाहिए।
DLosc

1
आपको इसे काटने में सक्षम होना चाहिए x.a==1and x(y)or u(a(x.a-1)(b.partial(x,y)))- तार्किक ऑपरेटर अभी भी शॉर्ट-सर्कुलेटिंग हैं, लेकिन टर्नरी की तुलना में कम वर्णों का उपयोग करते हैं। तब का उपयोग करके एक और बाइट बचाने x.a-1हालत (यदि 0 / गलत रूप में x1, अन्यथा है अशून्य / सही) और भाव 'शेष' अदला-बदली 'फिर' और: x.a-1and u(a(x.a-1)(b.partial(x,y)))or x(y)। (कुछ और अब आप मुझे पारित किया है कि गोल्फ की खान मिल जाएगा; ^);)
DLOS

1
मेरे साथ एक समान समस्या में भाग लेने के बाद, मुझे समझ में आया कि अब क्या विफल हो रहा है - अगर x.a==1यह सच है लेकिन x(y)कुछ गलत है, तो यह मूल्यांकन करने की कोशिश करता है u(...)। लेकिन ऐसा लगता है जैसे आपको खसरा 3 बाइट्स को बचाने की ज़रूरत नहीं है जो आपको दिया होगा! मैंने स्वीकार किया, सर: आपने मुझे पीछे छोड़ दिया है।
डीएलओएस

1
बस एक वक्रोक्ति: निर्दिष्ट आउटपुट स्वरूप में स्थान नहीं है - आप विभिन्न रणनीतियों द्वारा हल कर सकते हैं , यह सुनिश्चित नहीं है कि कौन सा सबसे छोटा है। बेशक, आपका कार्यक्रम संभालता है, RuntimeErrorजबकि मेरा सिर्फ उपयोगकर्ता को stderr को पुनर्निर्देशित करने के लिए कहता है ... इसलिए हम शायद क्विबल्स पर भी हैं। ; ^)
DLosc

1
*_लंबोदर में किस लिए है ?
mbomb007

4

Ghostscript

अभी तक गोल्फ नहीं हुआ है, क्योंकि मुझे अभी भी पार्सिंग फंक्शन की जरूरत है।

इस कार्यान्वयन का उपयोग करता है _और :के बजाय >और /, और यह सभी कार्यक्रम पात्रों रिक्त स्थान से अलग किया जा करने के लिए की आवश्यकता है। इसका कारण यह है >और /पोस्टस्क्रिप्ट में मान्य नाम नहीं हैं, और ऑपरेटरों स्वयं परिसीमन नहीं हैं, लेकिन जब मैं पार्सर लिखने ठीक किया जाएगा।

कोड का पहला भाग काफी पारदर्शी होना चाहिए, क्योंकि यह केवल ऑपरेटर कार्यों की परिभाषाओं को दोहरा रहा है। जादू की परिभाषा में होता है !

/switch {
    /y exch def
    /x exch def
    {x} {y} ifelse
} bind def

/unwrap {
    dup type (arraytype) eq {aload pop} if
} bind def

/! { % IN: <x> <f> OUT: <g>|<f(x)>
    [ 3 1 roll unwrap] cvx %prefix argument into function
    dup /fun exch def %bind

    [ count 1 roll ] { %run the function sandboxed so it can't take any additional args
        2 dict begin
        /=only {} def % suppress output
            {
                fun
            } stopped /err exch def clear err
        end
    } .runandhide


    exch {
        $error /errorname get
        (stackunderflow) ne {
            handleerror
        } if

        $error /newerror false put

        unwrap
    } {
        unwrap exec
    } ifelse
} def

/? 0 def
/+ {{dup}} def
/_ {{/f exch def pop f}} def % using _ instead of >
/: {{? ne 3 1 roll switch}} def % using : instead of /
/$ {{!}} def
/. {{/g exch def exec g}} def 
/@ {{dup ? eq {0}{1} ifelse =only}} def

जिस तरह से !काम करता है वह सरल है: सबसे पहले, यह तर्क xको सामग्री की fउपसर्ग द्वारा जोड़ देता है, इसे स्टैक पर वापस धकेलता है, और परिणाम की एक प्रति का नामकरण करता है ।xffun

यह फिर एक सरणी के रूप में पूरे ढेर को लपेटता है। .runandhideएक है Ghostscript विस्तार सैंडबॉक्स कोड चल रहा है, प्रक्रिया उस पर शुरू हो जाती है से पूर्ववर्ती सरणी की सामग्री को छिपाने के लिए। dictआदेश dict ढेर पर एक नया शब्दकोश धक्का, जब तक भीतर परिभाषित नाम के दायरे को कम endपॉप्स यह पीछे। यह एक डमी एक के साथ =only(आउटपुट ऑपरेटर मैं उपयोग करता है @) को भी चलाता है, ट्रायल रन के दौरान आउटपुट को दबाता है। stoppedपोस्टस्क्रिप्ट tryअन्य भाषाओं में पाए जाने वाले कथन के बराबर है , और यह सच है अगर इसकी प्रक्रिया में कोई त्रुटि है, और यह पूरा होने पर गलत है।

एक बार ट्रायल रन funपूरा होने के बाद, प्रोग्राम छिपे हुए सरणी से मूल स्टैक को पुनर्स्थापित करता है, और यदि funत्रुटि के बिना पूरा हो जाता है, तो यह आउटपुट रखते हुए वास्तविक के लिए चलाता है।


2

पायथन 3, 685 670 634 633 बाइट्स

मुझे पूरा यकीन है कि यह सबसे लंबी चीज है जिसे मैंने कभी गढ़ा है। यह कुछ हद तक पठनीय हुआ करता था, लेकिन @ sirpercival की सलाह के बाद उस खामी को खत्म कर दिया गया !

from re import*
E,*k="E"
P="e(k.pop(),k.pop())"
def H(a,b):global k;k+=list(a)+[N(b)];exec("k+=%s;"%P*Z(N(b)));return[]
def e(a,b):a=sub("(?<!\d)0",repr(N(b,1)).replace("\\",r"\\"),a,1);return Z(a)and[a]or list(eval(a))
D=list(zip("ilhydsSNZ",[3,2,2]+[1]*6,sub("A","N(a)",',b,c:[N([b,c][a>E])]|,b:e(A,N(b))|,b:["H(%s,%s)"%(A,repr(b))]|:print(0+(a>E),end="")or[A]|:[A]*2|:["S(0,%s)"%A]|,b:b+[A]|,b=-1:sub("\d+",lambda m:str(int(m.group())+b),a)|:len(split("\D0",a))-1').split("|")))
for n,r,f in D:exec(n+"=lambda a"+f)
F=dict(zip("/$.@+>?!",D))
for z in input():n,r,f=F[z];k+=z!="!"and[[n+"(%s)"%",".join("0"*r),E][z=="?"]]or eval(P)

kस्टैक है, जिसमें स्ट्रिंग्स के रूप में प्रतिनिधित्व किए गए फ़ंक्शन होते हैं जैसे "h(0,0)"(जो सी एच ऐन है )। जब किसी फ़ंक्शन को किसी अन्य फ़ंक्शन के तर्क के रूप में पास किया जाता है, तो वह repr'd और सभी संख्याएँ बढ़ जाती हैं "h('h(1,1)',0)":। एक बार जब सभी 0s को एक फ़ंक्शन में बदल दिया जाता है, तो पूरी चीज़ को पास कर दिया जाता है eval, जिससे उपयुक्त पायथन फ़ंक्शन को कॉल किया जाता है - जिनमें से अधिकांश लैम्बडा फ़ंक्शन execलाइन 7 में लाइन 6 द्वारा बड़े स्ट्रिंग से उत्पन्न होते हैं ।

नेस्टेड कार्यों के कई स्तर प्राप्त करना, उद्धृत करना, और ठीक से बच निकलना सबसे बड़ा सिरदर्द था। मैं regex संचालन पर थोड़ा और अधिक बचा सकता था अगर मैं यह मान सकता था कि फ़ंक्शन नेस्टिंग 9 स्तरों से अधिक गहरा नहीं होगा, लेकिन जैसा कि टिप्पणियों में बताया गया है कि शायद एक सुरक्षित धारणा नहीं है।

कोड का पूर्ववर्ती संस्करण Ungolfed:

from re import *
E="E"
stack=[]

clone=lambda a:[unnest(a)]*2
shift=lambda a:["shifted(0,%s)"%unnest(a)]
fork=lambda a,b,c:[unnest(c if a!=E else b)]
call=lambda a,b:apply(unnest(a),unnest(b))
chain=lambda a,b:["chained(%s,%s)"%(unnest(a),repr(b))]
def say(a):
 print(1 if a!=E else 0,end="")
 return [unnest(a)]

shifted=lambda a,b:b+[unnest(a)]
def chained(a,b):
 global stack
 stack+=list(a)+[unnest(b)]
 exec("stack+=apply(stack.pop(),stack.pop());"*zeros(unnest(b)))
 return []

nest=lambda a,direction:sub("\d+",lambda m:str(int(m.group())+direction),a)
unnest=lambda a:nest(a,-1)
zeros=lambda a:len(split("\D0",a))-1
def apply(a,b):
 a=sub("(?<!\d)0",repr(nest(b,1)).replace("\\",r"\\"),a,1)
 return [a] if zeros(a) else list(eval(a))

functions=dict(zip("+>/$.@",zip(["clone","shift","fork","call","chain","say"],[1,1,3,2,2,1])))

for cmd in input():
 if"!"==cmd:
  stack+=apply(stack.pop(),stack.pop())
 elif"?"==cmd:
  stack+=[E]
 else:
  name,arity=functions[cmd]
  stack+=[name+"(%s)"%",".join("0"*arity)]

इस कार्यान्वयन का एक संभावित दोष यह है कि यह पुनरावृत्ति का उपयोग करता है, इसलिए जिन कार्यक्रमों को अनंत होना चाहिए, वे अधिकतम पुनरावृत्ति की गहराई को बहुत तेज़ी से मारते हैं। (जब आप अनंत कार्यक्रम चलाते हैं, तो आप शायद स्ट्रीडर को पुनर्निर्देशित करना चाहते हैं - अन्यथा स्टैक ट्रेस वास्तविक आउटपुट को बदल देगा।) इसके अलावा, सब कुछ काम करने लगता है।


क्या आप ऐसा प्रोग्राम लिख सकते हैं जो उपरोक्त प्रोग्राम बनाता है और फिर इसे निष्पादित करता है? आपके पास बहुत सारे आवर्ती कोड हैं जो कि जैसे संकुचित होने चाहिए lambda aऔर k.pop()
mbomb007

@ mbomb007 ... मुझे लगता है कि मेरा दिमाग फट जाएगा। (लेकिन हाल ही में संपादित देखें - मैंने k.pop()वैसे भी स्थिति को थोड़ा कम दोहरावदार बना दिया ।)
DLosc

क्या आप उन सभी लंबों के लिए निष्पादन / अनुवाद ट्रिक कर सकते हैं? एक तार में उन सब को छड़ी?
बजे तक सैपरसिवल

एक अन्य टिप्पणी: मुझे संदेह है कि आप इस भाषा के साथ फंक्शन नेस्टिंग <= 9 पर भरोसा कर सकते हैं
साहचर्य

@ सिस्पिरिवल हाँ, मैं कोशिश कर रहा था कि सोच रहा था। और नहीं, मुझे नहीं लगता। : ^ पी
डीएलोस्क

1

सीलोन, 1167 1057 1031

मुझे यह नहीं मिला कि मोनो-टाइप अजगर संस्करणों के रूप में छोटा ...

import ceylon.language.meta.model{N=Function}import ceylon.collection{H=HashMap}interface D of F|b{}object b satisfies D{}class F(shared Integer a,[D+](D+)f,[D*]c=[])satisfies D{shared[D+]o(D i){[D+]s=[i].prepend(c);return a==1then f(*s)else[F(a-1,f,s)];}shared[D+]y([D+]i){return f(*i.prepend(c));}}F m<A>(N<[D+],A>f)given A satisfies[D+]=>F(f.parameterTypes.size,(D+i)=>f.apply(*i));[D,D]e(D x)=>[x,x];[F]t(F f){[D+]g(D+i){assert(is[D+]r=i.rest);return[i[0],*f.y(r)];}return[F(f.a+1,g)];}[D]k(D a,D d,D c)=>a==b then[d]else[c];[D+]l(F a,D x)=>a.o(x);[F]n(F f,F g){[D+]h(D+i){[D+]r=f.y(i);assert(is[D+]d=r[0:g.a]);return g.y(d).append(r[g.a...]);}return[F(f.a,h)];}[D]y(D x){process.write(x==b then"0"else"1");return[x];}class I(){variable D[]s=[];value c=H{'?'->b,'+'->m(`e`),'>'->m(`t`),'/'->m(`k`),'$'->m(`l`),'.'->m(`n`),'@'->m(`y`)};shared void r(Character i){if(i=='!'){assert(is F f=s[0],is D x=s[1]);s=f.o(x).append(s[2...]);}else{assert(is D d=c[i]);s=[d].append(s);}}}shared void z(){process.readLine()?.collect(I().r);}

यहाँ एक ही कोड का एक स्वरूपित (और टिप्पणी) संस्करण है (रिक्त स्थान / newlines / टिप्पणियों के साथ यह 4867 बाइट्स हो जाता है):

import ceylon.language.meta.model {
    N=Function
}
import ceylon.collection {
    H=HashMap
}
//↑ Import of stuff we need – with a shorter alias.
// (The comment is down here due to a bug in my comment and space
//  remover – it doesn't remove a comment if it is the first token
//  at all.)

// Our data items are either functions or blanks.
interface D of F | b {}

// There is no point in having many blanks – so here a singleton.
object b satisfies D {}

// The function class. Our functions take a number of data items,
// and return a number of data items.
// We know the arity a, and have also an actual function f, and a number
// or already collected arguments.
class F(shared Integer a, [D+](D+) f, [D*] c = [])
        satisfies D {
    // apply once (= collect one parameter). Returns either the result,
    // or a function with arity one less.
    shared [D+] o(D i) {
        [D+] s = [i].prepend(c);
        return a == 1 then f(*s) else [F(a - 1, f, s)];
    }
    // apply fully (= with all needed parameters).
    // The input size should equal the arity.
    shared [D+] y([D+] i) {
        // merge collected and input arguments.
        return f(*i.prepend(c));
    }
}
// creates a shift function from a ceylon function,
// deriving the arity using reflection.
F m<A>(N<[D+],A> f)
        given A satisfies [D+]
        => F(f.parameterTypes.size, (D+ i) => f.apply(*i));

//
// clone: a unary function that duplicates its input: any value x is mapped to [x,x].
//
[D, D] e(D x) => [x, x];

//
// shift: a unary function that takes in an n-ary function f, and returns an
// (n+1)-ary function g that ignores its first argument x, calls f on the
// remaining ones, and tacks x in front of the result. For example,
// shift(clone) is a binary function that takes inputs a,b and returns [a,b,b].
//
[F] t(F f) {
    [D+] g(D+ i) {
        assert (is [D+] r = i.rest);
        return [i[0], *f.y(r)];
    }
    return [F(f.a + 1, g)];
}

//
// fork: a ternary function that takes three inputs a,d,c, and returns [d] if a is a blank,
// and [c] otherwise.
//
[D] k(D a, D d, D c) => a == b then [d] else [c];

//
// call: a binary function that pops a function f and a value x,
//        and applies f to x exactly as ! does.
//
[D+] l(F a, D x) => a.o(x);

//
// chain:  a binary function that pops two functions f and g, and returns their composition:
//         a function h that has the same arity as f, and which takes its inputs normally, applies
//         f to them, and then fully applies g to the result (calls it as many times as its arity
//         dictates), with unused items from the output of f remaining in the result of h. For
//         example, suppose that f is a binary function that clones its second argument, and
//         g is call. If the stack contains [f,g,a,b,c] and we do .!!, then it contains
//         [chain(f,g),a,b,c]; if we do !! next, then f is first applied to a,b, producing
//         [a,b,b], then g is applied to the first two elements of that since its arity is 2,
//         producing [a(b),b], and the stack will finally be [a(b),b,c].
//
[F] n(F f, F g) {
    [D+] h(D+ i) {
        // call f, remember the results.
        [D+] r = f.y(i);
        // first some results from f are the arguments to g:
        assert (is [D+] d = r[0:g.a]);
        // remaining results from f are passed back directly, with the results from g.
        return g.y(d).append(r[g.a...]);
    }
    return [F(f.a, h)];
}

//
// say: a unary function that simply returns its input, and prints 0 if it was a blank,
//      and 1 if it was a function.
// 
[D] y(D x) {
    process.write(x == b then "0" else "1");
    return [x];
}

//
// Interpreter class, which manages the stack and interprets the commands.
// Just call the r method with the individual command characters.
//
class I() {
    // The stack. The only variable in the whole program.
    variable D[] s = [];

    // a hash map of items to be pushed by commands, most build using the m function.
    // The apply command is not here, this is handled separately by the interpreter. 
    value c = H {
        '?'->b,
        '+'->m(`e`),
        '>'->m(`t`),
        '/'->m(`k`),
        '$'->m(`l`),
        '.'->m(`n`),
        '@'->m(`y`)
    };

    // Interprets one command, indicated by a character.
    // Will throw an AssertionError for unknown commands.
    shared void r(Character i) {
        if (i == '!') {
            assert (
                is F f = s[0],
                is D x = s[1]);
            // apply f on x, push the result onto a shortened version of the stack.
            s = f.o(x).append(s[2...]);
        } else {
            assert (is D d = c[i]);
            // push d on top of the stack.
            s = [d].append(s);
        }
    }
}

shared void z() {
    process.readLine()?.collect(I().r);
}

कार्यों क्लोन e, पाली t, कांटा k, कॉल l, कहते हैं yऔर श्रृंखला nसंक्षिप्त संस्करण के लिए नामों की अंतिम अक्षर का उपयोग करें, क्योंकि है कि कम टकराव दे दी है। (सामान्य ज्ञान: कांटा मूल रूप से इस तरह से परिभाषित किया गया था [Data] fork(Data a, Data b, Data c) => a == blank then [b] else [c];- जब मैं नाम दिया blankकरने के लिए b, इस तोड़ दिया, क्योंकि यह अब मानकों की तुलना में aऔर bके बजाय aखाली साथ मुझे डिबग के लिए कुछ समय लिया।।)

zक्योंकि मेरे आईडीई उन कार्यों चलाता समारोह साझा किया जाता है - कमांड लाइन टूल भी गैर साझा लोगों चला सकते हैं।


लूपिंग संस्करण वास्तव में कुछ बिंदु पर एक StackOverflowError फेंक देंगे, फिर परिष्करण। JVM में रिकर्सन स्टैक ऑप्टिमाइज़ेशन नहीं है (या कम से कम कोई भी जो मेरे प्रोग्राम के लिए काम करेगा)।
पाओलो एबरमन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.