拙作のページ「遅延ストリーム 前編, 後編」で作成したプログラムをモジュール化したものです。学習が目的のプログラムなので実用性はありませんが、興味のある方は試してみてください。
julia> a = @delay (println("oops!"); 1 + 2 * 3) Lazy.Promise(var"#1#2"(), false, nothing) julia> force(a) oops! 7 julia> force(a) 7
julia> nils LazyStream()
julia> isempty(nils) true julia> s1 = @cons(1, @cons(2, @cons(3, nils))) LazyStream(1, ?) julia> head(s1) 1 julia> tail(s1) LazyStream(2, ?) julia> head(tail(s1)) 2 julia> head(tail(tail(s1))) 3 julia> tail(tail(tail(s1))) LazyStream()
julia> s = unfold(x -> x + 1, 1) LazyStream(1, ?) julia> for _ = 1 : 10 print("$(head(s)) ") global s = tail(s) end 1 2 3 4 5 6 7 8 9 10 julia> s = tolazy(1 : 10) LazyStream(1, ?) julia> for _ = 1 : 10 print("$(head(s)) ") global s = tail(s) end 1 2 3 4 5 6 7 8 9 10 julia> s LazyStream() julia> s1 = circle(1,2,3) LazyStream(1, ?) julia> for _ = 1 : 10 print("$(head(s1)) ") global s1 = tail(s1) end 1 2 3 1 2 3 1 2 3 1 julia> s1 LazyStream(2, ?) julia> circle() LazyStream() julia> s2 = cycle(1 : 4) LazyStream(1, ?) julia> for _ = 1 : 10 print("$(head(s2)) ") global s2 = tail(s2) end 1 2 3 4 1 2 3 4 1 2 julia> s2 LazyStream(3, ?) julia> cycle([]) LazyStream()
julia> s = unfold(x -> x + 1, 1) LazyStream(1, ?) julia> nth(s, 1) 1 julia> nth(s, 10) 10 julia> nth(s, 100) 100 julia> s1 = tolazy(1:2:10) LazyStream(1, ?) julia> s2 = tolazy(2:2:10) LazyStream(2, ?) julia> s3 = append(s1, s2) LazyStream(1, ?) julia> for i = 1 : 10 print("$(nth(s3, i)) ") end 1 3 5 7 9 2 4 6 8 10 julia> s3 = interleave(s1, s2) LazyStream(1, ?) julia> for i = 1 : 10 print("$(nth(s3, i)) ") end 1 2 3 4 5 6 7 8 9 10 julia> s3 = reverse(s1) LazyStream(9, ?) julia> for i = 1 : 5 print("$(nth(s3, i)) ") end 9 7 5 3 1 julia> s4 = take(s, 10) LazyStream(1, ?) julia> for i = 1 : 10 print("$(nth(s4, i)) ") end 1 2 3 4 5 6 7 8 9 10 julia> drop(s4, 10) LazyStream() julia> drop(s, 10) LazyStream(11, ?) julia> s4 = takewhile(x -> x < 6, s) LazyStream(1, ?) julia> for i = 1 : 5 print("$(nth(s4, i)) ") end 1 2 3 4 5 julia> s4 = dropwhile(x -> x < 6, s) LazyStream(6, ?) julia> for i = 1 : 5 print("$(nth(s4, i)) ") end 6 7 8 9 10
julia> s1 = map(x -> x * x, s) LazyStream(1, ?) julia> for i = 1 : 10 print("$(nth(s1, i)) ") end 1 4 9 16 25 36 49 64 81 100 julia> s2 = flatmap(x -> tolazy(1:x), s) LazyStream(1, ?) julia> for i = 1 : 20 print("$(nth(s2, i)) ") end 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 1 2 3 4 5 julia> s3 = filter(iseven, s) LazyStream(2, ?) julia> for i = 1 : 20 print("$(nth(s3, i)) ") end 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 julia> foldl(+, take(s, 10), 0) 55 julia> foldr(+, take(s, 10), 0) 55 julia> foreach(println, take(s, 10)) 1 2 3 4 5 6 7 8 9 10
julia> s = unfold(x -> x + 1, 1) LazyStream(1, ?) julia> for x = take(s, 10) print("$x ") end 1 2 3 4 5 6 7 8 9 10 julia> for x = zip(take(s, 10), map(x -> x*x, s)) print(x) end (1, 1)(2, 4)(3, 9)(4, 16)(5, 25)(6, 36)(7, 49)(8, 64)(9, 81)(10, 100) julia> for x = enumerate(take(map(x -> x*x, s), 10)) print(x) end (1, 1)(2, 4)(3, 9)(4, 16)(5, 25)(6, 36)(7, 49)(8, 64)(9, 81)(10, 100) julia> all(x -> x < 10, takewhile(x -> x < 10, s)) true julia> all(x -> x < 10, takewhile(x -> x < 11, s)) false julia> any(iseven, take(s, 10)) true julia> any(iseven, take(filter(isodd, s), 10)) false
julia> s1 = unfold(x -> x + 2, 1) LazyStream(1, ?) julia> s2 = unfold(x -> x + 2, 2) LazyStream(2, ?) julia> s3 = merge(s1, s2) LazyStream(1, ?) julia> foreach(println, take(s3, 10)) 1 2 3 4 5 6 7 8 9 10 julia> for x = unique(tolazy([1,1,2,2,3,3,4,4,5,5])) println(x) end 1 2 3 4 5 julia> s1 = tolazy(1:8) LazyStream(1, ?) julia> s2 = tolazy(4:12) LazyStream(4, ?) julia> for x in union(s1, s2) print("$x ") end 1 2 3 4 5 6 7 8 9 10 11 12 julia> for x in intersect(s1, s2) print("$x ") end 4 5 6 7 8
# # Lazy.jl : 遅延評価と遅延ストリーム # # Copyright (C) 2016-2021 Makoto Hiroi # # module Lazy export @delay, force, LazyStream, nils, @cons, head, tail, unfold, tolazy, circle, cycle export nth, take, takewhile, drop, dropwhile, append, interleave, append_delay, flatmap import Base: isempty, iterate, show, reverse, map, filter, foldl, foldr, foreach, merge import Base: unique, union, intersect # # 遅延評価 # # プロミス mutable struct Promise func flag::Bool value end macro delay(expr) :(Promise(() -> $(esc(expr)), false, nothing)) end function force(p::Promise) if !p.flag p.value = p.func() p.flag = true end p.value end # # 遅延ストリーム # abstract type LazyStream end # 終端 struct Nil <: LazyStream end # 定数 const nils = Nil() # 終端の判定 Base.isempty(s::LazyStream) = s === nils # 遅延ストリーム struct Cons <: LazyStream head tail::Promise end # ストリームを生成するマクロ macro cons(x, s) esc(:(Lazy.Cons($x, @delay $s))) end # アクセス関数 head(s::Nil) = nils head(s::Cons) = s.head tail(s::Nil) = nils tail(s::Cons) = force(s.tail) # イテレータ function iterate(s::LazyStream, state = s) if isempty(state) nothing else (head(state), tail(state)) end end # 表示 function show(io::IO, s::LazyStream) if isempty(s) print(io, "LazyStream()") else print(io, "LazyStream($(head(s)), ?)") end end # 遅延ストリームの生成 function unfold(iter::Function, seed, cond::Function = _ -> false) if cond(seed) nils else @cons(seed, unfold(iter, iter(seed), cond)) end end # イテレータを遅延ストリームに変換する function tolazy(iter, state = nothing) next = state === nothing ? iterate(iter) : iterate(iter, state) if next === nothing nils else @cons(next[1], tolazy(iter, next[2])) end end # 引数を無限に繰り返す function circle(args...; idx = 1) if isempty(args) nils else @cons(args[idx], circle(args..., idx = length(args) == idx ? 1 : idx + 1)) end end # イテレータを無限に繰り返す function cycle(iter, state = nothing) if state == nothing next = iterate(iter) if next === nothing return nils end else next = iterate(iter, state) if next === nothing next = iterate(iter) end end @cons(next[1], cycle(iter, next[2])) end # n 番目の要素を求める function nth(s::LazyStream, n::Int) while n > 1 if isempty(s) error("nth: empty stream") end s = tail(s) n -= 1 end head(s) end # 先頭から n 個の要素を取り出す function take(s::LazyStream, n::Int) if isempty(s) || n <= 0 nils else @cons(head(s), take(tail(s), n - 1)) end end # 先頭から n 個の要素を取り除く function drop(s::LazyStream, n::Int) while !isempty(s) && n > 0 s = tail(s) n -= 1 end s end # 関数 pred が真を返す間、先頭から要素を取り出す function takewhile(pred, s::LazyStream) if isempty(s) || !pred(head(s)) nils else @cons(head(s), takewhile(pred, tail(s))) end end # 関数 pred が真を返す間、先頭から要素を取り除く function dropwhile(pred, s::LazyStream) while !isempty(s) && pred(head(s)) s = tail(s) end s end # 連結 function append(s1::LazyStream, s2::LazyStream) if isempty(s1) s2 else @cons(head(s1), append(tail(s1), s2)) end end function interleave(s1::LazyStream, s2::LazyStream) if isempty(s1) s2 else @cons(head(s1), interleave(s2, tail(s1))) end end # 反転 function reverse(s::LazyStream) if isempty(s) nils else append(reverse(tail(s)), @cons(head(s), nils)) end end # # 高階関数 # # マッピング function map(func::Function, xs::LazyStream...) if any(isempty, xs) nils else @cons(func(map(head, xs)...), map(func, map(tail, xs)...)) end end # フィルター function filter(pred::Function, s::LazyStream) while !isempty(s) if pred(head(s)) return @cons(head(s), filter(pred, tail(s))) end s = tail(s) end nils end # 畳み込み function foldl(f::Function, s::LazyStream, a) while !isempty(s) a = f(a, head(s)) s = tail(s) end a end function foldr(f::Function, s::LazyStream, a) if isempty(s) a else f(head(s), foldr(f, tail(s), a)) end end # 巡回 function foreach(f::Function, s::LazyStream) while !isempty(s) f(head(s)) s = tail(s) end end function append_delay(s1::LazyStream, s2::Promise) if isempty(s1) force(s2) else @cons(head(s1), append_delay(tail(s1), s2)) end end # 遅延ストリームの平坦化 function flatmap(f::Function, s::LazyStream) if isempty(s) s else append_delay(f(head(s)), @delay flatmap(f, tail(s))) end end # # 併合と集合演算 # # 以下の関数はストリームの要素が昇順で並んでいることを前提としている # # 遅延ストリームの併合 function merge(s1::LazyStream, s2::LazyStream) if isempty(s1) s2 elseif isempty(s2) s1 elseif head(s1) <= head(s2) @cons(head(s1), merge(tail(s1), s2)) else @cons(head(s2), merge(s1, tail(s2))) end end # 重複要素の削除 function unique(s::LazyStream) if isempty(s) s else @cons(head(s), unique(dropwhile(x -> x == head(s), tail(s)))) end end # 和集合 function union(s1::LazyStream, s2::LazyStream) if isempty(s1) s2 elseif isempty(s2) s1 elseif head(s1) < head(s2) @cons(head(s1), union(tail(s1), s2)) elseif head(s1) == head(s2) @cons(head(s1), union(tail(s1), tail(s2))) else @cons(head(s2), union(s1, tail(s2))) end end # 積集合 function intersect(s1::LazyStream, s2::LazyStream) while !isempty(s1) && !isempty(s2) if head(s1) == head(s2) return @cons(head(s1), intersect(tail(s1), tail(s2))) elseif head(s1) < head(s2) s1 = tail(s1) else s2 = tail(s2) end end nils end end
リスト : たらいまわし関数 # 通常版 function tarai(x, y, z) if x <= y y else tarai(tarai(x - 1, y, z), tarai(y - 1, z, x), tarai(z - 1, x, y)) end end # 遅延評価版 function tarai1(x, y, z) if x <= y y else zz = force(z) tarai1(tarai1(x - 1, y, @delay zz), tarai1(y - 1, zz, @delay x), @delay tarai1(zz - 1, x, @delay y)) end end
julia> @time tarai(14, 7, 0) 1.878156 seconds 14 julia> @time tarai1(14, 7, @delay 0) 0.053478 seconds (16.86 k allocations: 1.185 MiB, 99.09% compilation time) 14 実行環境 : Julia ver 1.10.5, Ubuntu 22.04 (WSL2), Intel Core i5-6200U 2.30GHz
リスト : 数列の生成 # 整数列 (有限) integers(low, high) = unfold(x -> x + 1, low, x -> x > high) # 1 から始まる整数列 (無限) ints = unfold(x -> x + 1, 1) # フィボナッチ数 fibonacci(a, b) = @cons(a, fibonacci(b, a + b)) fibos = @cons(0, @cons(1, map(+, tail(fibos), fibos)))
julia> foreach(x -> print("$x "), integers(1, 10)) 1 2 3 4 5 6 7 8 9 10 julia> foreach(x -> print("$x "), take(ints, 10)) 1 2 3 4 5 6 7 8 9 10 julia> foreach(x -> print("$x "), take(fibonacci(0, 1), 10)) 0 1 1 2 3 5 8 13 21 34 julia> foreach(x -> print("$x "), take(fibos, 10)) 0 1 1 2 3 5 8 13 21 34 julia> nth(fibos, 40) 63245986 julia> nth(fibos, 50) 7778742049
リスト : 直積集合 (有限) function product(s1::LazyStream, s2::LazyStream) flatmap(x -> map(y -> (x, y), s2), s1) end
julia> s1 = tolazy(1:5) LazyStream(1, ?) julia> s2 = tolazy(6:10) LazyStream(6, ?) julia> s3 = product(s1, s2) LazyStream((1, 6), ?) julia> foreach(print, s3) (1, 6)(1, 7)(1, 8)(1, 9)(1, 10) (2, 6)(2, 7)(2, 8)(2, 9)(2, 10) (3, 6)(3, 7)(3, 8)(3, 9)(3, 10) (4, 6)(4, 7)(4, 8)(4, 9)(4, 10) (5, 6)(5, 7)(5, 8)(5, 9)(5, 10)
リスト : 直積集合 (無限) function product_inf(s1::LazyStream, s2::LazyStream, n = 1) append_delay(map((x, y) -> (x, y), take(s1, n), reverse(take(s2, n))), @delay product_inf(s1, s2, n + 1)) end
julia> s = unfold(x -> x + 1, 1) LazyStream(1, ?) julia> s1 = product_inf(s, s) LazyStream((1, 1), ?) julia> foreach(print, take(s1, 55)) (1, 1) (1, 2)(2, 1) (1, 3)(2, 2)(3, 1) (1, 4)(2, 3)(3, 2)(4, 1) (1, 5)(2, 4)(3, 3)(4, 2)(5, 1) (1, 6)(2, 5)(3, 4)(4, 3)(5, 2)(6, 1) (1, 7)(2, 6)(3, 5)(4, 4)(5, 3)(6, 2)(7, 1) (1, 8)(2, 7)(3, 6)(4, 5)(5, 4)(6, 3)(7, 2)(8, 1) (1, 9)(2, 8)(3, 7)(4, 6)(5, 5)(6, 4)(7, 3)(8, 2)(9, 1) (1, 10)(2, 9)(3, 8)(4, 7)(5, 6)(6, 5)(7, 4)(8, 3)(9, 2)(10, 1)
リスト : 二次元の格子点 lattice2() = unfold(st -> st[1] == 0 ? (st[2] + 1, 0) : (st[1] - 1, st[2] + 1), (0, 0))
julis> s = lattice2() LazyStream((0, 0), ?) julis> foreach(print, take(s, 55)) (0, 0) (1, 0)(0, 1) (2, 0)(1, 1)(0, 2) (3, 0)(2, 1)(1, 2)(0, 3) (4, 0)(3, 1)(2, 2)(1, 3)(0, 4) (5, 0)(4, 1)(3, 2)(2, 3)(1, 4)(0, 5) (6, 0)(5, 1)(4, 2)(3, 3)(2, 4)(1, 5)(0, 6) (7, 0)(6, 1)(5, 2)(4, 3)(3, 4)(2, 5)(1, 6)(0, 7) (8, 0)(7, 1)(6, 2)(5, 3)(4, 4)(3, 5)(2, 6)(1, 7)(0, 8) (9, 0)(8, 1)(7, 2)(6, 3)(5, 4)(4, 5)(3, 6)(2, 7)(1, 8)(0, 9)
出力は手作業で整形しています。
リスト : d 次元格子点の生成 function lattice_sub(d::Int, n::Int) if d == 1 @cons((n,), nils) elseif n == 0 @cons(Tuple(zeros(Int, d)), nils) else flatmap(x -> map(xs -> (x, xs...), lattice_sub(d - 1, n - x)), tolazy(0 : n)) end end function lattice(d::Int) flatmap(n -> lattice_sub(d, n), unfold(x -> x + 1, 0)) end
julis> s1 = lattice(1) LazyStream((0,), ?) julis> foreach(print, take(s1, 60)) (0,)(1,)(2,)(3,)(4,)(5,)(6,)(7,)(8,)(9,)(10,)(11,)(12,)(13,)(14,)(15,)(16,)(17,) (18,)(19,)(20,)(21,)(22,)(23,)(24,)(25,)(26,)(27,)(28,)(29,)(30,)(31,)(32,)(33,) (34,)(35,)(36,)(37,)(38,)(39,)(40,)(41,)(42,)(43,)(44,)(45,)(46,)(47,)(48,)(49,) (50,)(51,)(52,)(53,)(54,)(55,)(56,)(57,)(58,)(59,) julis> s2 = lattice(2) LazyStream((0, 0), ?) julis> foreach(print, take(s2, 60)) (0, 0)(0, 1)(1, 0)(0, 2)(1, 1)(2, 0)(0, 3)(1, 2)(2, 1)(3, 0)(0, 4)(1, 3)(2, 2) (3, 1)(4, 0)(0, 5)(1, 4)(2, 3)(3, 2)(4, 1)(5, 0)(0, 6)(1, 5)(2, 4)(3, 3)(4, 2) (5, 1)(6, 0)(0, 7)(1, 6)(2, 5)(3, 4)(4, 3)(5, 2)(6, 1)(7, 0)(0, 8)(1, 7)(2, 6) (3, 5)(4, 4)(5, 3)(6, 2)(7, 1)(8, 0)(0, 9)(1, 8)(2, 7)(3, 6)(4, 5)(5, 4)(6, 3) (7, 2)(8, 1)(9, 0)(0, 10)(1, 9)(2, 8)(3, 7)(4, 6) julis> s3 = lattice(3) LazyStream((0, 0, 0), ?) julis> foreach(print, take(s3, 60)) (0, 0, 0)(0, 0, 1)(0, 1, 0)(1, 0, 0)(0, 0, 2)(0, 1, 1)(0, 2, 0)(1, 0, 1)(1, 1, 0) (2, 0, 0)(0, 0, 3)(0, 1, 2)(0, 2, 1)(0, 3, 0)(1, 0, 2)(1, 1, 1)(1, 2, 0)(2, 0, 1) (2, 1, 0)(3, 0, 0)(0, 0, 4)(0, 1, 3)(0, 2, 2)(0, 3, 1)(0, 4, 0)(1, 0, 3)(1, 1, 2) (1, 2, 1)(1, 3, 0)(2, 0, 2)(2, 1, 1)(2, 2, 0)(3, 0, 1)(3, 1, 0)(4, 0, 0)(0, 0, 5) (0, 1, 4)(0, 2, 3)(0, 3, 2)(0, 4, 1)(0, 5, 0)(1, 0, 4)(1, 1, 3)(1, 2, 2)(1, 3, 1) (1, 4, 0)(2, 0, 3)(2, 1, 2)(2, 2, 1)(2, 3, 0)(3, 0, 2)(3, 1, 1)(3, 2, 0)(4, 0, 1) (4, 1, 0)(5, 0, 0)(0, 0, 6)(0, 1, 5)(0, 2, 4)(0, 3, 3) julis> s4 = lattice(4) LazyStream((0, 0, 0, 0), ?) julis> foreach(print, take(s4, 60)) (0, 0, 0, 0)(0, 0, 0, 1)(0, 0, 1, 0)(0, 1, 0, 0)(1, 0, 0, 0)(0, 0, 0, 2)(0, 0, 1, 1) (0, 0, 2, 0)(0, 1, 0, 1)(0, 1, 1, 0)(0, 2, 0, 0)(1, 0, 0, 1)(1, 0, 1, 0)(1, 1, 0, 0) (2, 0, 0, 0)(0, 0, 0, 3)(0, 0, 1, 2)(0, 0, 2, 1)(0, 0, 3, 0)(0, 1, 0, 2)(0, 1, 1, 1) (0, 1, 2, 0)(0, 2, 0, 1)(0, 2, 1, 0)(0, 3, 0, 0)(1, 0, 0, 2)(1, 0, 1, 1)(1, 0, 2, 0) (1, 1, 0, 1)(1, 1, 1, 0)(1, 2, 0, 0)(2, 0, 0, 1)(2, 0, 1, 0)(2, 1, 0, 0)(3, 0, 0, 0) (0, 0, 0, 4)(0, 0, 1, 3)(0, 0, 2, 2)(0, 0, 3, 1)(0, 0, 4, 0)(0, 1, 0, 3)(0, 1, 1, 2) (0, 1, 2, 1)(0, 1, 3, 0)(0, 2, 0, 2)(0, 2, 1, 1)(0, 2, 2, 0)(0, 3, 0, 1)(0, 3, 1, 0) (0, 4, 0, 0)(1, 0, 0, 3)(1, 0, 1, 2)(1, 0, 2, 1)(1, 0, 3, 0)(1, 1, 0, 2)(1, 1, 1, 1) (1, 1, 2, 0)(1, 2, 0, 1)(1, 2, 1, 0)(1, 3, 0, 0)
リスト : 多角数 # 三角数 triangulars = map(x -> div(x * (x + 1), 2), ints) # 四角数 squares = map(x -> x * x, ints) # 平方三角数 trisquares = intersect(triangulars, squares)
julia> foreach(x -> print("$x "), take(triangulars, 10)) 1 3 6 10 15 21 28 36 45 55 julia> foreach(x -> print("$x "), take(squares, 10)) 1 4 9 16 25 36 49 64 81 100 julia> foreach(x -> print("$x "), take(trisquares, 7)) 1 36 1225 41616 1413721 48024900 1631432881
リスト : ハミングの問題 hammings = @cons(1, union(union(map(x -> 2x, hammings), map(x -> 3x, hammings)), map(x -> 5x, hammings)))
julia> foreach(x -> print("$x "), take(hammings, 100)) 1 2 3 4 5 6 8 9 10 12 15 16 18 20 24 25 27 30 32 36 40 45 48 50 54 60 64 72 75 80 81 90 96 100 108 120 125 128 135 144 150 160 162 180 192 200 216 225 240 243 250 256 270 288 300 320 324 360 375 384 400 405 432 450 480 486 500 512 540 576 600 625 640 648 675 720 729 750 768 800 810 864 900 960 972 1000 1024 1080 1125 1152 1200 1215 1250 1280 1296 1350 1440 1458 1500 1536
リスト : FizzBuzz 問題 function fizzbuzz() function change(x, y, z) m = y + z if m == 0 string(x) elseif m == 1 "Fizz" elseif m == 2 "Buzz" else "FizzBuzz" end end map(change, unfold(x -> x + 1, 1), circle(0,0,1), circle(0,0,0,0,2)) end
julia> for x = take(fizzbuzz(), 100) print("$x ") end 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz 16 17 Fizz 19 Buzz Fizz 22 23 Fizz Buzz 26 Fizz 28 29 FizzBuzz 31 32 Fizz 34 Buzz Fizz 37 38 Fizz Buzz 41 Fizz 43 44 FizzBuzz 46 47 Fizz 49 Buzz Fizz 52 53 Fizz Buzz 56 Fizz 58 59 FizzBuzz 61 62 Fizz 64 Buzz Fizz 67 68 Fizz Buzz 71 Fizz 73 74 FizzBuzz 76 77 Fizz 79 Buzz Fizz 82 83 Fizz Buzz 86 Fizz 88 89 FizzBuzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz
リスト : 順列の生成 function permutations(n::Int, s::LazyStream) if n == 0 @cons([], nils) else flatmap(s) do x map(y -> vcat([x], y), permutations(n - 1, filter(z -> x != z, s))) end end end
julia> foreach(println, permutations(4, integers(1, 4))) Any[1, 2, 3, 4] Any[1, 2, 4, 3] Any[1, 3, 2, 4] Any[1, 3, 4, 2] Any[1, 4, 2, 3] Any[1, 4, 3, 2] Any[2, 1, 3, 4] Any[2, 1, 4, 3] Any[2, 3, 1, 4] Any[2, 3, 4, 1] Any[2, 4, 1, 3] Any[2, 4, 3, 1] Any[3, 1, 2, 4] Any[3, 1, 4, 2] Any[3, 2, 1, 4] Any[3, 2, 4, 1] Any[3, 4, 1, 2] Any[3, 4, 2, 1] Any[4, 1, 2, 3] Any[4, 1, 3, 2] Any[4, 2, 1, 3] Any[4, 2, 3, 1] Any[4, 3, 1, 2] Any[4, 3, 2, 1]
リスト : 組み合わせの生成 function combinations(n::Int, s::LazyStream) if n == 0 @cons([], nils) elseif isempty(s) nils else append_delay(map(y -> vcat([head(s)], y), combinations(n - 1, tail(s))), @delay combinations(n, tail(s))) end end
julia> foreach(println, combinations(3, integers(1, 5))) Any[1, 2, 3] Any[1, 2, 4] Any[1, 2, 5] Any[1, 3, 4] Any[1, 3, 5] Any[1, 4, 5] Any[2, 3, 4] Any[2, 3, 5] Any[2, 4, 5] Any[3, 4, 5]
リスト : エラトステネスの篩 function sieve(s) if isempty(s) s else x = head(s) @cons(x, sieve(filter(n -> n % x != 0, tail(s)))) end end
julia> ps = sieve(unfold(x -> x + 1, 2)) LazyStream(2, ?) julia> foreach(x -> print("$x "), take(ps, 25)) 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 julia> @time nth(ps, 5000) 8.239483 seconds (88.39 M allocations: 2.069 GiB, 63.92% gc time, 0.17% compilation time) 48611 実行環境 : Julia ver 1.10.5, Ubunts 22.04 (WSL2), Intel Core i5-6200U 2.30GHz
リスト : 素数列 (遅延ストリーム) primes = @cons(2, @cons(3, @cons(5, primesfrom(7)))) # 素数の生成 function primesfrom(n) while true if isprime1(n) return @cons(n, primesfrom(n + 2)) end n += 2 end end # n は素数か function isprime(n) all(x -> n % x != 0, takewhile(p -> p * p <= n, primes)) end # こちらのほうがもっと速い function isprime1(n) s = primes while true x = head(s) if n % x == 0 return false elseif x * x > n return true end s = tail(s) end end
julia> foreach(x -> print("$x "), take(primes, 25)) 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 julia>: @time nth(primes, 5000) 0.032148 seconds (762.82 k allocations: 11.867 MiB) 48611 実行環境 : Julia ver 1.10.5, Ubunts 22.04 (WSL2), Intel Core i5-6200U 2.30GHz
リスト : 双子素数 twinprimes = filter(xs -> xs[2] - xs[1] == 2, map((x, y) -> (x, y), primes, tail(primes)))
julia> foreach(x -> print("$x "), take(twinprimes, 100)) (3, 5) (5, 7) (11, 13) (17, 19) (29, 31) (41, 43) (59, 61) (71, 73) (101, 103) (107, 109) (137, 139) (149, 151) (179, 181) (191, 193) (197, 199) (227, 229) (239, 241) (269, 271) (281, 283) (311, 313) (347, 349) (419, 421) (431, 433) (461, 463) (521, 523) (569, 571) (599, 601) (617, 619) (641, 643) (659, 661) (809, 811) (821, 823) (827, 829) (857, 859) (881, 883) (1019, 1021) (1031, 1033) (1049, 1051) (1061, 1063) (1091, 1093) (1151, 1153) (1229, 1231) (1277, 1279) (1289, 1291) (1301, 1303) (1319, 1321) (1427, 1429) (1451, 1453) (1481, 1483) (1487, 1489) (1607, 1609) (1619, 1621) (1667, 1669) (1697, 1699) (1721, 1723) (1787, 1789) (1871, 1873) (1877, 1879) (1931, 1933) (1949, 1951) (1997, 1999) (2027, 2029) (2081, 2083) (2087, 2089) (2111, 2113) (2129, 2131) (2141, 2143) (2237, 2239) (2267, 2269) (2309, 2311) (2339, 2341) (2381, 2383) (2549, 2551) (2591, 2593) (2657, 2659) (2687, 2689) (2711, 2713) (2729, 2731) (2789, 2791) (2801, 2803) (2969, 2971) (2999, 3001) (3119, 3121) (3167, 3169) (3251, 3253) (3257, 3259) (3299, 3301) (3329, 3331) (3359, 3361) (3371, 3373) (3389, 3391) (3461, 3463) (3467, 3469) (3527, 3529) (3539, 3541) (3557, 3559) (3581, 3583) (3671, 3673) (3767, 3769) (3821, 3823)