Last active
April 1, 2017 22:13
-
-
Save mratsim/9814240f00598a7e9889a2458a447e86 to your computer and use it in GitHub Desktop.
Unfolding Nim magic
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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