Skip to content

Instantly share code, notes, and snippets.

@mratsim
Last active April 1, 2017 22:13
Show Gist options
  • Select an option

  • Save mratsim/9814240f00598a7e9889a2458a447e86 to your computer and use it in GitHub Desktop.

Select an option

Save mratsim/9814240f00598a7e9889a2458a447e86 to your computer and use it in GitHub Desktop.
Unfolding Nim magic
import options
import future
import sequtils
# Unfolding the Nim Magic
## Bug https://github.com/nim-lang/Nim/issues/5647 open.
## unfold proper type signature should have Option[(T, U)] instead of Option[(T, T)]
# proc unfoldr*[T, U](f: U -> Option[(T, U)], x:U): seq[T] {. inline .}=
proc unfoldr[T, U](f: T -> Option[(T, T)], x:U): seq[T] {. inline .}=
## Build a sequence from function f: T -> Option(T,T) and a seed of type T
result = @[]
var a: U = x
var b: T
var fa = f(a)
while fa.isSome():
(b, a) = fa.get()
result.add(b)
fa = f(a)
proc unfoldrIter[T, U](f: T -> Option[(T, T)], x:U): iterator():T =
## Build an iterator from function f: T -> Option(T,T) and a seed of type T
## Useful to consume infinite generators like power of 2 and fibonacci
result = iterator(): T {.closure.}=
var a: U = x
var b: T
var fa = f(a)
while fa.isSome():
(b, a) = fa.get()
yield b
fa = f(a)
###### 1. Get the digits from a number
proc divmod10(n: int): Option[(int, int)] =
if n == 0:
return none((int,int))
return some(( (n mod 10).int(), n div 10))
proc toDigits*(n: int): seq[int] =
unfoldr(divmod10,n)
proc reverse[T](xs: openarray[T]): seq[T] =
## Reverse a sequence or array and output a sequence
result = newSeq[T](xs.len)
for i, x in xs:
result[^i-1] = x
echo "1. Unfolding your 123456 digits"
echo toDigits(123456).reverse # @[1, 2, 3, 4, 5, 6]
###### 2. Get your power of 2 below 100000
proc takeWhile*[T](iter: iterator(): T, cond: proc(x: T):bool): iterator(): T =
result = iterator(): T {.closure.}=
var r = iter()
while not finished(iter) and cond(r):
yield r
r = iter()
proc pow2(x: int): Option[(int,int)] = some((x, x*2))
echo "\n2. Unfolding power of 2 below 100 000"
var power_generator = unfoldrIter(pow2, 2).takeWhile(x => x< 100_000)
echo power_generator().toseq # @[2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536]
# ###### X. Get your Fibonacci sequence - waiting for https://github.com/nim-lang/Nim/issues/5647
# proc fibonacciGenerator( a, b: int ): Option[(int, (int,int))] =
# some((a+b, (b, a+b))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment