{"id":198,"date":"2006-10-28T12:52:52","date_gmt":"2006-10-28T12:52:52","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/2006\/10\/28\/more-fractran-a-trivial-interpreter\/"},"modified":"2006-10-28T12:52:52","modified_gmt":"2006-10-28T12:52:52","slug":"more-fractran-a-trivial-interpreter","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2006\/10\/28\/more-fractran-a-trivial-interpreter\/","title":{"rendered":"More Fractran: A Trivial Interpreter"},"content":{"rendered":"<p>For your amusement and edification, the following is a very simple interpreter for fractran<br \/>\nprograms which, in addition to running the program to generate its result also generates a trace<br \/>\nto show you how the program executed.<br \/>\n;; A Trivial Fractran Interpreter<br \/>\n;;<br \/>\n;; Copyright 2006 Mark C. Chu-Carroll<br \/>\n;; http:\/\/scienceblogs.com\/goodmath<br \/>\n;;<br \/>\n;; You&#8217;re welcome to do anything you want with this code as long<br \/>\n;; as you keep a copy of this header to identify the original source.<br \/>\n;;<br \/>\n;; This program runs a fractran program. A fractran program is a list<br \/>\n;; of fractions. The fractions are represented by a list of two integers:<br \/>\n;; the numerator, and the denominator. For example, the classic fractran<br \/>\n;; multiplication program could be written:<br \/>\n;;     ((385 13) (13 21) (1 7) (3 11) (7 2) (1 3))<br \/>\n;; or:<br \/>\n;;     (((* 7 11 5) 13) (13 (* 3 7)) (1 7) (3 11) (7 2) (1 3))<br \/>\n;;<br \/>\n;;<br \/>\n;; To run a program until it terminates, call (run-fractran program input).<br \/>\n;; This will return a list; the car of the list will be the result of<br \/>\n;; running the program, and the cdr will be a trace of the executions in the<br \/>\n;; form of a list of the fractions that ran at each step.<br \/>\n;;<br \/>\n;; To run a program for a specific maximum number of steps, call<br \/>\n;; (run-fractran-bounded program input maxsteps)<br \/>\n;;<br \/>\n(define (step-fractran fract int)<br \/>\n(if (equal? fract ()) int<br \/>\n(let ((fr (car fract)))<br \/>\n(if (= (remainder int (cadr fr)) 0)<br \/>\n(cons (\/ (* int (car fr)) (cadr fr))<br \/>\n(list fr))<br \/>\n(step-fractran (cdr fract) int)))))<br \/>\n(define (run-fractran fract int)<br \/>\n(let ((step-result (step-fractran fract int)))<br \/>\n(if (list? step-result)<br \/>\n(let ((new-int (car step-result))<br \/>\n(last-step (cadr step-result)))<br \/>\n(cons step-result (run-fractran fract new-int)))<br \/>\n(list int ))))<br \/>\n(define (run-fractran-bounded fract int bound)<br \/>\n(if (&gt; bound 0)<br \/>\n(let ((step-result (step-fractran fract int)))<br \/>\n(if (list? step-result)<br \/>\n(let ((new-int (car step-result))<br \/>\n(last-step (cadr step-result)))<br \/>\n(cons step-result (run-fractran-bounded fract new-int (- bound 1))))<br \/>\n(list int)))<br \/>\n(list int)))<br \/>\n;; The mult program.<br \/>\n(define mult &#8216;((385 13) (13 21) (1 7) (3 11) (7 2) (1 3)))<br \/>\n;;<br \/>\n;; (run-fractran mult 432)<br \/>\n;; The primes program<br \/>\n(define primes &#8216;((17 91) (78 85) (19 51) (23 38) (29 33) (77 29) (95 23)<br \/>\n(77 19) (1 17) (11 13) (13 11) (15 2) (1 7) (55 1)))<br \/>\n;; (run-fractran-bounded primes 2 1000)<br \/>\n&#8212;&#8212;&#8212;-<br \/>\nCommenter Pseudonym has kindly provided a Haskell version in the comments, which was mangled by MTs comment formatting, so I&#8217;m adding a properly formatted version here. I think it&#8217;s a really interesting comparison to the scheme code above. The Haskell code is very nice; cleaner than my rather slapdash Scheme version. But overall, I think it&#8217;s a pretty good comparison &#8211; it gives you a sense of what the same basic code looks like in the two languages.  Personally, I think the Haskell is clearer than the Scheme, even though the Scheme is my own code.<br \/>\nmodule Fractran where<br \/>\nimport Ratio<br \/>\nimport Data.Maybe<br \/>\nimport Control.Monad.Fix<br \/>\ntype Program = [Rational]<br \/>\nrunFractran :: [()] -&gt; Program -&gt; Integer -&gt; [Integer]<br \/>\nrunFractran bound prog l<br \/>\n= step bound prog l<br \/>\nwhere<br \/>\nstep _ [] l = []<br \/>\nstep [] (f:fs) l<br \/>\n= []<br \/>\nstep (_:bound) (f:fs) l<br \/>\n= let p = f * fromIntegral l<br \/>\nin case denominator p of<br \/>\n1 -&gt; let pi = numerator p<br \/>\nin pi : step bound prog pi<br \/>\n_ -&gt; step bound fs l<br \/>\nfractran :: Program -&gt; Integer -&gt; [Integer]<br \/>\nfractran prog l<br \/>\n= runFractran (fix (():)) prog l<br \/>\nfractranBounded :: Int -&gt; Program -&gt; Integer -&gt; [Integer]<br \/>\nfractranBounded b prog l<br \/>\n= runFractran (take b $ fix (():)) prog l<br \/>\nmult = [385%13, 13%21, 1%7, 3%11, 7%2, 1%3]<br \/>\nprimes = [17%91, 78%85, 19%51, 23%38, 29%33, 77%29, 95%23,<br \/>\n77%19, 1%17, 11%13, 13%11, 15%2, 1%7, 55%1]<br \/>\n&#8212; fractran mult (2^4 * 3^3)<br \/>\n&#8212; fractranBounded 1000 primes 2<\/p>\n","protected":false},"excerpt":{"rendered":"<p>For your amusement and edification, the following is a very simple interpreter for fractran programs which, in addition to running the program to generate its result also generates a trace to show you how the program executed. ;; A Trivial Fractran Interpreter ;; ;; Copyright 2006 Mark C. Chu-Carroll ;; http:\/\/scienceblogs.com\/goodmath ;; ;; You&#8217;re welcome [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[92],"tags":[],"class_list":["post-198","post","type-post","status-publish","format-standard","hentry","category-pathological-programming"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-3c","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/198","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/comments?post=198"}],"version-history":[{"count":1,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/198\/revisions"}],"predecessor-version":[{"id":3832,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/198\/revisions\/3832"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=198"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=198"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=198"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}