Given this Python code:

def f(k):
	n = 2 << k
	q = 2
	i = 1
	while q != n:
		
		i *= q
		
		q <<= 1
	return i

The Elixir translation is roughly the following:

def f(k) do
	n = 2 <<< k # Remember to add "use Bitwise" at the top of the module
	q = 2
	i = 1
	# (Storing the output into a tuple for reasons that will be explained later)
	{i, _, _} = Stream.unfold({q, i}, fn # Initial values: current scope's q and i
		{^n, _} -> nil # Loop halt condition: q == n (fixing the current scope's value of n)
		{q, i} -> # Loop takes 2 arguments: q, i (inside a tuple)
			
			i = i * q
			
			{ # Return a 2-tuple to the `Stream.unfold` interface:
				# 1st element gets yielded to the outer scope:
				{i, :fyi, "You can return multiple values here if you want to"},
				# 2nd element is fed back in as the argument to the next iteration of the loop:
				{q <<< 1, i}
	 		}
	end)
	|> Enum.take(-1) # Stream.unfold yields all values; only take the last
	|> hd # Convert 1-element list into its component element
	i
end

Generalizing further, we get:

hd(Enum.take(Stream.unfold({nil, VARS}, fn
	{:halt, _} -> nil
	{_, VARS} ->
		WHILE_BODY(VARS) # _do_ modify VARS within this
		{RETVAL(VARS), {if(EXIT_PREDICATE(VARS), do: :halt), VARS}}
end), -1))

(where VARS may be either a bare variable or a tuple of them)

TODO: translate that last codeblock into defmacro while…


Of course, the above code is a maximalist, generalizable example—it is a template that you can take and fill with the most convoluted looped code you care to write (so long as you enumerate the variables that get changed each loop and shunt them away into the return value); in reality, computing the above function per se would be very simple since it's inherently a kind of accumulation; something like the following would do:

def f(k) do
	q = 2
	Enum.product(Stream.map(0..(k-1), fn k -> (q <<< k) end))
end

Leave a Reply

Your email address will not be published.

Warning: This site uses Akismet to filter spam. Until or unless I can find a suitable replacement anti-spam solution, this means that (per their indemnification document) all commenters' IP addresses will be sent to Automattic, Inc., who may choose to share such with 3rd parties.
If this is unacceptable to you, I highly recommend using an anonymous proxy or public Wi-Fi connection when commenting.