Question

I apologize in advance for asking this question again. I asked this question previously with respect to a Haskell implementation here, but I'm still having difficulty wrapping my head around how this works. Also, I find the concept of a minimalistic programming language absolutely fascinating and can't get away from it... anyways, this is no place to be nostalgic about the beauty of functional programming.

So! I found a website about esoteric programming languages and discovered Iota. Iota is arguably the smallest functional language. You can read more about it here: "Iota and Jot: the simplest languages?" Here is the reference implementation of Iota in Scheme:

(let iota ()
   (if (eq? #\* (read-char)) ((iota)(iota))
       (lambda (c) ((c (lambda (x) (lambda (y) (lambda (z) ((x z)(y z))))))
                    (lambda (x) (lambda (y) x))))))

But, when I try something equivalent in elegance to the Scheme implementation in Ruby it ends up spitting out a "bad proc". Can anyone help me understand why Ruby is behaving this way and how this can be implemented better. While trying to get this to work, I kept S, K, and BASIS separate just for readability.

I included two tests at the bottom. The first should return I (BASIS[BASIS]), but instead it returns a proc that doesn't produce the same result as I. The second test should return K, but instead it returns an error.

S = lambda {|f| lambda {|g| lambda {|x| f[x][g[x]] }}}
K = lambda {|x| lambda {|y| x }}
BASIS = lambda {|c| c[S][K] }

iota = lambda{|s|
   s = s.chars
   i = lambda {
      if s.next == '*'
         i[i]
      else
         BASIS
      end
   }
}

p BASIS[BASIS][1]         # => 1
p iota["*ii"][1]          # => #<Proc:0x000000010016b290>

p K[1][2]                 # => 1
p iota["*i*i*ii"][1][2]   # => line 3:in `[]': can't convert Proc into Integer (TypeError)
Was it helpful?

Solution 2

Thanks to sepp2k I think I figured it out, here's the answer for anyone who's interested:

S = lambda {|f| lambda {|g| lambda {|x| f[x][g[x]] }}}
K = lambda {|x| lambda {|y| x }}
BASIS = lambda {|c| c[S][K] }

iota = lambda{|s|
   s = s.chars
   i = lambda {
      if s.next == '*'
         i[][i[]]
      else
         BASIS
      end
   }
   i[]
}

p BASIS[BASIS][1]          # => 1
p iota["*ii"][1]           # => 1

p K[1][2]                  # => 1
p iota["*i*i*ii"][1][2]    # => 1

OTHER TIPS

On line 9, you're calling i[i], but i doesn't take any arguments - only the lambda returned by i does. So you should call i with no arguments and then call the result of calling i with i as its argument, i.e. i[][i].

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top