Advertisement
Guest User

Untitled

a guest
Oct 27th, 2016
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.19 KB | None | 0 0
  1. local lazy = {};
  2. local unpack = table.unpack or unpack
  3.  
  4. -- Create a coroutine that delays evaluation of `x`.
  5. function lazy.delay(x, ...)
  6. local args = {...}
  7. return coroutine.create(function()
  8. if #args >= 1 then
  9. return x(unpack(args))
  10. end
  11. return x
  12. end)
  13. end
  14.  
  15. -- Force-evaluate a coroutine.
  16. -- This function is strict in it's first argument, therefore
  17. -- force(bot) = bot
  18. -- Where bot is the bottom value, represented in Lua through
  19. -- a diverging call to `error`.
  20. --
  21. function lazy.force(x)--{{{
  22. if type(x) == 'thread' then
  23. if coroutine.status(x) ~= 'dead' then
  24. local ok, err = coroutine.resume(x)
  25. if not ok then
  26. error('Coroutine being force-evaluated diverged with error message: ' .. err, 0)
  27. else
  28. return err
  29. end
  30. else
  31. error('Can not force-evaluate dead coroutine: ' .. tostring(x), 0)
  32. end
  33. else
  34. return x
  35. end
  36. end--}}}
  37.  
  38. -- Force-evaluate a coroutine, with a default value.
  39. -- This function, while strict in its first argument will not
  40. -- diverge if the passed coroutine diverges. Instead, the
  41. -- default argument will be used instead.
  42.  
  43. function lazy.force_or(x, def)--{{{
  44. if type(x) == 'thread' then
  45. if coroutine.status(x) ~= 'dead' then
  46. local ok, err = coroutine.resume(x)
  47. if not ok then
  48. return def
  49. else
  50. return err
  51. end
  52. else
  53. return def
  54. end
  55. else
  56. return x
  57. end
  58. end--}}}
  59.  
  60. function lazy.eval(...)--{{{
  61. return lazy.from_list({...}):reduce(function(x, y)
  62. lazy.force(x)
  63. return lazy.force(y)
  64. end):last()
  65. end--}}}
  66.  
  67. function lazy.also(...) --{{{
  68. local args = {...}
  69. return function(x)
  70. local ret = x
  71. for k, v in pairs(args) do
  72. ret = v(ret)
  73. end
  74. return x
  75. end
  76. end --}}}
  77.  
  78. lazy.Stream = {}
  79.  
  80. local function mkstream(coro)--{{{
  81. assert(type(coro) == 'thread' or type(coro) == 'function', 'expected a coroutine or a function as first parameter of stream constructor')
  82. if type(coro) == 'function' then
  83. return setmetatable({thread = coroutine.create(coro)}, lazy.Stream)
  84. else
  85. return setmetatable({thread = coro}, lazy.Stream)
  86. end
  87. end--}}}
  88.  
  89. setmetatable(lazy.Stream, { __call = mkstream })
  90. lazy.Stream.__call = mkstream
  91. lazy.Stream.__concat = lazy.Stream.concat
  92. lazy.Stream.__index = lazy.Stream;
  93. lazy.Stream.__type = 'stream'
  94.  
  95. function lazy.Stream:__tostring()--{{{
  96. local x = {}
  97. local i = 1
  98. while self:has_next() do
  99. local e = self:next()
  100. if type(x) == 'string' then
  101. x[i] = ("%q"):format(e)
  102. else
  103. x[i] = tostring(e)
  104. end
  105. i = i + 1
  106. end
  107. return '[' .. table.concat(x, ', ') .. ']'
  108. end--}}}
  109.  
  110. function lazy.Stream:print()--{{{
  111. io.write '['
  112. while self:has_next() do
  113. local x = self:next()
  114. if type(x) == 'string' then
  115. io.write(("'%s', ")
  116. :format(x))
  117. elseif type(x) == 'stream' then
  118. x:print()
  119. else
  120. io.write(("%s, ")
  121. :format(x))
  122. end
  123. end
  124. print ']'
  125. end--}}}
  126.  
  127. function lazy.Stream:cons(a)--{{{
  128. assert(a, 'expected a value as the first argument of Stream:cons')
  129. return mkstream(function()
  130. coroutine.yield(a)
  131. while self:has_next() do
  132. coroutine.yield(self:next())
  133. end
  134. end)
  135. end--}}}
  136.  
  137. function lazy.Stream:cons_mut(a) --{{{
  138. assert(a, 'expected a value as the first argument of Stream:cons')
  139. self.thread = coroutine.create(function()
  140. coroutine.yield(a)
  141. while self:has_next() do
  142. coroutine.yield(self:next())
  143. end
  144. end)
  145. end --}}}
  146.  
  147. function lazy.Stream:snoc_mut(a) --{{{
  148. assert(a, 'expected a value as the first argument of Stream:cons')
  149. self.thread = coroutine.create(function()
  150. while self:has_next() do
  151. coroutine.yield(self:next())
  152. end
  153. coroutine.yield(a)
  154. end)
  155. end --}}}
  156.  
  157. function lazy.Stream:snoc(a) --{{{
  158. assert(a, 'expected a value as the first argument of Stream:snoc')
  159. return mkstream(function()
  160. while self:has_next() do
  161. coroutine.yield(self:next())
  162. end
  163. coroutine.yield(a)
  164. end)
  165. end --}}}
  166.  
  167. function lazy.Stream:has_next()--{{{
  168. if coroutine.status(self.thread) ~= 'dead' then
  169. local val = lazy.force_or(self.thread, nil)
  170. self.__cached_val = val
  171. return val ~= nil
  172. else
  173. return false
  174. end
  175. end--}}}
  176.  
  177. function lazy.Stream:next()--{{{
  178. if self.__cached_val ~= nil then
  179. local val = self.__cached_val
  180. self.__cached_val = nil
  181. return val
  182. else
  183. return lazy.force_or(self.thread, nil)
  184. end
  185. end--}}}
  186.  
  187. function lazy.Stream:peek() --{{{
  188. if self.__cached_val ~= nil then
  189. return self.__cached_val
  190. else
  191. self.__cached_val = lazy.force_or(self.thread, nil)
  192. return self.__cached_val
  193. end
  194. end --}}}
  195.  
  196. function lazy.Stream:pull()--{{{
  197. if coroutine.status(self.thread) == 'dead' then
  198. return false
  199. else
  200. local ok, res = coroutine.resume(self.thread)
  201. if coroutine.status(self.thread) == 'dead' then
  202. return false
  203. elseif ok then
  204. return true, res
  205. else
  206. error(res)
  207. end
  208. end
  209. end--}}}
  210.  
  211. function lazy.Stream:length()--{{{
  212. local i = 0
  213. while self:has_next() do
  214. i = i + 1
  215. self:next()
  216. end
  217. return i
  218. end--}}}
  219.  
  220. function lazy.Stream:uncons()--{{{
  221. return self:next(), self
  222. end--}}}
  223.  
  224. function lazy.Stream:unsnoc() --{{{
  225. return self:init(), self:last()
  226. end --}}}
  227.  
  228. function lazy.Stream:head()--{{{
  229. return self:head()
  230. end--}}}
  231.  
  232. function lazy.Stream:tail()--{{{
  233. return mkstream(function()
  234. self:next()
  235. while self:has_next() do
  236. coroutine.yield(self:next())
  237. end
  238. end)
  239. end--}}}
  240.  
  241. function lazy.Stream:last()--{{{
  242. return self:fold(function(_, x) return x end, _.delay(error, "last: empty stream"))
  243. end--}}}
  244.  
  245. function lazy.Stream:init()--{{{
  246. return mkstream(function()
  247. local ok, v1 = self:pull()
  248. while true do
  249. local ok, v2 = self:pull()
  250. if ok then
  251. coroutine.yield(v1)
  252. v1 = v2
  253. else
  254. break
  255. end
  256. end
  257. end)
  258. end--}}}
  259.  
  260. function lazy.Stream:drop(n)--{{{
  261. assert(type(n) == 'number', 'expected the number of elements to drop as the first argument of Stream:drop')
  262. return mkstream(function()
  263. for i = 1, n do
  264. if self:has_next() then
  265. self:next()
  266. else
  267. return
  268. end
  269. end
  270. while self:has_next() do
  271. coroutine.yield(self:next())
  272. end
  273. end)
  274. end--}}}
  275.  
  276. function lazy.Stream:take(n)--{{{
  277. assert(type(n) == 'number', 'expected the number of elements to take as the first argument of Stream:take')
  278. return mkstream(function()
  279. for i = 1, n do
  280. if self:has_next() then
  281. coroutine.yield(self:next())
  282. end
  283. end
  284. end)
  285. end--}}}
  286.  
  287. function lazy.Stream:map(fun)--{{{
  288. assert(type(fun) == 'function', 'expected a function to map with as the first argument of Stream:map')
  289. return mkstream(function()
  290. while self:has_next() do
  291. local x = self:next()
  292. local x_ = fun(x)
  293. if x_ ~= nil then
  294. coroutine.yield(x_)
  295. else
  296. break
  297. end
  298. end
  299. end)
  300. end--}}}
  301.  
  302. function lazy.Stream:filter(fun)--{{{
  303. assert(type(fun) == 'function', 'expected a predicate function as the first argument of Stream:filter')
  304. return mkstream(function()
  305. while self:has_next() do
  306. local x = self:next()
  307. if fun(x) then
  308. coroutine.yield(x)
  309. end
  310. end
  311. end)
  312. end--}}}
  313.  
  314. function lazy.Stream:concat(b)--{{{
  315. assert(getmetatable(b) == lazy.Stream, 'expected a stream to concatenate with as the second argument (right-hand side) of Stream:map')
  316. return mkstream(function()
  317. while self:has_next() do
  318. coroutine.yield(lazy.force(self:next()))
  319. end
  320. while coroutine.status(b) ~= 'dead' do
  321. coroutine.yield(lazy.force(b))
  322. end
  323. end)
  324. end--}}}
  325.  
  326. function lazy.Stream:zip(fun, ls, ...)--{{{
  327. assert(getmetatable(ls) == lazy.Stream, 'expected a stream as the second argument of Stream:zip')
  328. assert(type(fun) == 'function', 'expected a function as the first argument of Stream:zip')
  329. local args = {ls, ...}
  330. local function allAlive(args)
  331. for i = 1, #args do
  332. if not args[i]:has_next() then
  333. return false
  334. end
  335. end
  336. return true
  337. end
  338. local function nextAll(args)
  339. local ret = {}
  340. for i = 1, #args do
  341. ret[i] = args[i]:next()
  342. end
  343. return ret
  344. end
  345. return mkstream(function()
  346. while self:has_next() and allAlive(args) do
  347. coroutine.yield(fun(self:next(), unpack(nextAll(args))))
  348. end
  349. end)
  350. end--}}}
  351.  
  352. function lazy.Stream:join(sep)--{{{
  353. assert(type(sep) == 'string', 'expected a string to use as the joiner')
  354. return self:fold(function(x, y)
  355. return x .. sep .. y
  356. end)
  357. end--}}}
  358.  
  359. function lazy.Stream:fold(fn, init)--{{{
  360. assert(type(fn) == 'function', 'expected a function to fold with as the first argument of Stream:fold')
  361. local accum = init or self:next()
  362. while self:has_next() do
  363. accum = fn(accum, self:next())
  364. end
  365. return lazy.force(accum)
  366. end--}}}
  367.  
  368. function lazy.Stream:flip() --{{{
  369. return self:fold(lazy.Stream.cons, lazy.null)
  370. end --}}}
  371.  
  372. function lazy.Stream:flatten() --{{{
  373. return mkstream(function()
  374. while self:has_next() do
  375. local x = self:next()
  376. if getmetatable(x) == lazy.Stream then
  377. while x:has_next() do
  378. coroutine.yield(x:next())
  379. end
  380. else
  381. coroutine.yield(x)
  382. end
  383. end
  384. end)
  385. end --}}}
  386.  
  387. function lazy.Stream:bind(f) --{{{
  388. return mkstream(function()
  389. while self:has_next() do
  390. local e = f(self:next())
  391. while e:has_next() do
  392. coroutine.yield(e:next())
  393. end
  394. end
  395. end)
  396. end --}}}
  397. lazy.Stream.flat_map = lazy.Stream.bind
  398.  
  399. function lazy.Stream:intercalate(x)--{{{
  400. return mkstream(function()
  401. local ok, v1 = self:pull()
  402. while true do
  403. local ok, v2 = self:pull()
  404. if ok then
  405. coroutine.yield(v1)
  406. coroutine.yield(x)
  407. v1 = v2
  408. else
  409. coroutine.yield(v1)
  410. break
  411. end
  412. end
  413. end)
  414. end--}}}
  415.  
  416. function lazy.Stream:collect()--{{{
  417. local i, c = {}, 1
  418. while self:has_next() do
  419. i[c] = self:next()
  420. c = c + 1
  421. end
  422. return i
  423. end--}}}
  424.  
  425. function lazy.Stream:iterator() --{{{
  426. return function()
  427. while self:has_next() do
  428. return self:next()
  429. end
  430. end
  431. end
  432. --}}}
  433.  
  434. function lazy.iterate(fn, x)--{{{
  435. assert(type(fn) == 'function', 'expected a generator function as the first argument of iterate')
  436. assert(x ~= nil, 'expected a seed')
  437. local ac = x
  438. return mkstream(function()
  439. while true do
  440. coroutine.yield(ac)
  441. ac = fn(ac)
  442. end
  443. end)
  444. end--}}}
  445.  
  446. function lazy.seq(x, en, inc)--{{{
  447. assert(type(x) == 'number' or type(x) == 'BigNum', 'expected a number or a bignumber for the start value of seq')
  448. local i = x
  449. if not inc then
  450. inc = 1
  451. else
  452. inc = inc - x
  453. end
  454. return mkstream(function()
  455. while true do
  456. if (not en) or (en >= i) then
  457. coroutine.yield(i)
  458. i = i + inc
  459. else
  460. break
  461. end
  462. end
  463. end)
  464. end--}}}
  465.  
  466. function lazy.unfold(gen, seed)--{{{
  467. assert(type(gen) == 'function', 'expected a generator function as the first argument to unfold')
  468. assert(seed, 'expected a seed value as the second argument to unfold')
  469. return mkstream(function()
  470. while true do
  471. local ok, val = gen(seed)
  472. if ok then
  473. seed = val
  474. coroutine.yield(ok)
  475. else
  476. break
  477. end
  478. end
  479. end)
  480. end--}}}
  481.  
  482. function lazy.replicate(x, times)--{{{
  483. assert(x, 'expected a value to replicate')
  484. if times and type(times) == 'number' then
  485. return mkstream(function()
  486. for i = 1, times do
  487. coroutine.yield(x)
  488. end
  489. end)
  490. else
  491. return mkstream(function()
  492. while true do
  493. coroutine.yield(x)
  494. end
  495. end)
  496. end
  497. end --}}}
  498.  
  499. function lazy.from_list(lis)--{{{
  500. assert(type(lis) == 'table', 'expected a list as the first argument to from_list')
  501. return mkstream(function()
  502. for i = 1, #lis do
  503. coroutine.yield(lis[i])
  504. end
  505. end)
  506. end--}}}
  507.  
  508. function lazy.from_file(fil, mode, cnt)--{{{
  509. assert(type(fil) == 'string', 'expected a file path as the first argument to from_file')
  510. mode = mode or 'c'
  511. if mode == 'c' then
  512. return mkstream(function()
  513. local han = io.open(fil, 'r')
  514. if not han then
  515. error('file ' .. fil .. ' could not be opened for reading.')
  516. else
  517. local ch = han:read '*a'
  518. for i = 1, #ch do
  519. coroutine.yield(ch:sub(i,i))
  520. end
  521. han:close()
  522. end
  523. end)
  524. elseif mode == 'l' then
  525. return mkstream(function()
  526. local han = io.open(fil, 'r')
  527. if not han then
  528. error('file ' .. fil .. ' could not be opened for reading.')
  529. else
  530. for s in han:lines() do
  531. coroutine.yield(s)
  532. end
  533. han:close()
  534. end
  535. end)
  536. elseif mode == 'cb' and cnt then
  537. return mkstream(function()
  538. local han = io.open(fil, 'r')
  539. if not han then
  540. error('file ' .. fil .. ' could not be opened for reading.')
  541. else
  542. local all = han:read '*a'
  543. for i = 1, #all, cnt do
  544. coroutine.yield(all:sub(i, (i + cnt) - 1))
  545. end
  546. han:close()
  547. end
  548. end)
  549. elseif mode == 'w' then
  550. return mkstream(function()
  551. local han = io.open(fil, 'r')
  552. if not han then
  553. error('file ' .. fil .. ' could not be opened for reading.')
  554. else
  555. for s in han:lines() do
  556. for w in s:gmatch '[^ ]+' do
  557. coroutine.yield(w)
  558. end
  559. end
  560. han:close()
  561. end
  562. end)
  563. end
  564. end--}}}
  565.  
  566. function lazy.stdin(mode) --{{{
  567. mode = mode or 'l'
  568. if mode == 'w' then
  569. return mkstream(function()
  570. local x = io.read '*l'
  571. while x ~= nil do
  572. for w in x:gmatch '[^ ]+' do
  573. coroutine.yield(w)
  574. end
  575. x = io.read '*l'
  576. end
  577. end)
  578. else
  579. return mkstream(function()
  580. local x = io.read '*l'
  581. while x ~= nil do
  582. coroutine.yield(x)
  583. x = io.read '*l'
  584. end
  585. end)
  586. end
  587. end --}}}
  588.  
  589. function lazy.stdin_prompt(prompt, mode) --{{{
  590. mode = mode or 'l'
  591. if mode == 'w' then
  592. return mkstream(function()
  593. io.write(prompt)
  594. local x = io.read '*l'
  595. while x ~= nil do
  596. for w in x:gmatch '[^ ]+' do
  597. coroutine.yield(w)
  598. end
  599. io.write(prompt)
  600. x = io.read '*l'
  601. end
  602. end)
  603. else
  604. return mkstream(function()
  605. io.write(prompt)
  606. local x = io.read '*l'
  607. while x ~= nil do
  608. coroutine.yield(x)
  609. io.write(prompt)
  610. x = io.read '*l'
  611. end
  612. end)
  613. end
  614. end --}}}
  615.  
  616. function lazy.words(x) --{{{
  617. return mkstream(function()
  618. for w in x:gmatch '[^ ]+' do
  619. coroutine.yield(w)
  620. end
  621. end)
  622. end --}}}
  623.  
  624. lazy.null = mkstream(function() end)
  625.  
  626. do --{{{ Install type() override
  627. local typ = type
  628. function type(x)
  629. if typ(x) == 'table' then
  630. if getmetatable(x) and getmetatable(x).__type then
  631. return getmetatable(x).__type
  632. else
  633. return 'table'
  634. end
  635. else
  636. return typ(x)
  637. end
  638. end
  639. lazy.type = type
  640. lazy._type = typ
  641. end --}}}
  642.  
  643. return lazy
  644.  
  645. -- vim: fdm=marker ts=2 et
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement