[size=150][b]<whileの反復脱出をなしにしたい>[br][/b][b][br][color=#ff0000]よくあるwhile型の反復脱出プログラムを書こうとしたら、[br]このgeobebraテキストアプリが勝手に改造するバグがあるので、[br]かけない。[br][/color]例えば、簡単にいうと、res=trueにしておく。[br]while resとかを先頭にかく。[br]中に、約数があればres=falseにして反復を脱出してreturn resする。[br][/b][/size][br]では、whileなしで関数型にしよう。[br]まずは、100で実験してみる。[br][IN]julia[br][color=#38761d]# n=100に対して、[br]# 2から100-1までのリストを作る。その要素である数mで100を割る。[br]# 割り切れたら0,それ以外なら1をマッピングする。[br]# こうやって、[/color][color=#0000ff][b][size=150]脱出条件となる情報をひたすらメモする[/size][/b][/color][color=#38761d]のなら、[br]# 関数型・リスト型で行けそうだ![br][br][/color][color=#0000ff]n=100[br]try100=map(m-> n % m==0 ? 1 : 0 ,2:n-1)[br]println(try100)[br]#=====================[br][/color][OUT][br][1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0][br][color=#0000ff][br]次は本番。[br][/color][color=#0000ff][IN]julia[br][/color][color=#38761d]# 2から100までの数nに対して、[br]# 2からn-1までのリストを作る。その要素である数mでnを割る。[br]# 割り切れたら0,それ以外なら1をマッピングする。0か1を要素とする99個のリストのリストができる。[br]# 1つ1つのリストに対して、(n、0か1を合計)というタプルに変換する。[br]# nが素数なら2からn-1の間に約数がないから、合計は0になる。[br]# (n,0)のときに、nが素数になる。[br][/color][color=#0000ff]res=map(n->(n,sum(map(m-> n % m==0 ? 1 : 0 ,2:n-1))),2:100)[br]println(res)[br][/color][color=#0000ff]#=====================[br][/color][OUT][br][(2, 0), (3, 0), (4, 1), (5, 0), (6, 2), (7, 0), (8, 2), (9, 1), (10, 2), (11, 0), (12, 4), (13, 0), (14, 2), (15, 2), (16, 3), (17, 0), (18, 4), (19, 0), (20, 4), (21, 2), (22, 2), (23, 0), (24, 6), (25, 1), (26, 2), (27, 2), (28, 4), (29, 0), (30, 6), (31, 0), (32, 4), (33, 2), (34, 2), (35, 2), (36, 7), (37, 0), (38, 2), (39, 2), (40, 6), (41, 0), (42, 6), (43, 0), (44, 4), (45, 4), (46, 2), (47, 0), (48, 8), (49, 1), (50, 4), (51, 2), (52, 4), (53, 0), (54, 6), (55, 2), (56, 6), (57, 2), (58, 2), (59, 0), (60, 10), (61, 0), (62, 2), (63, 4), (64, 5), (65, 2), (66, 6), (67, 0), (68, 4), (69, 2), (70, 6), (71, 0), (72, 10), (73, 0), (74, 2), (75, 4), (76, 4), (77, 2), (78, 6), (79, 0), (80, 8), (81, 3), (82, 2), (83, 0), (84, 10), (85, 2), (86, 2), (87, 2), (88, 6), (89, 0), (90, 10), (91, 2), (92, 4), (93, 2), (94, 2), (95, 2), (96, 10), (97, 0), (98, 4), (99, 4), (100, 7)][br][color=#0000ff][br]#これでは、素数以外もまざるから、タプルの第2要素==0のときの第1要素だけを抜き出せば、[br]素数一覧になる。[br]map(x->x[1],filter(x->x[2]==0,res))[br][br][/color]これは、次のようにgeogebraでもいける。
[color=#38761d][b][u][size=150]質問:他のwhile脱出以外に、回数のわからない反復のコード化はできないのでしょうか。[br][br][/size][/u][/b][/color]whileを使う文脈は、調べる範囲や回数が未定な状況があるときです。[br]調査範囲の上限や最大値が事前にわかっていれば、そこまで回せがよいのですが、[br]終了条件を達成するための調査範囲の上限がわからないからこそ、実際にまわしてみるわけです。[br][br][color=#0000ff]ということは[b]リストが無限のサイズならば、リスト処理が可能[/b]になりますね。[br][b]本当は無限ではないのですが、特に決めておかないという形式の定義ならば無限も定義できます。[br][/b][/color][br]haskellでは無限の自然数列を定義しておき、[br][b][color=#0000ff]--[Haskell]============[br]infiniteList :: [Int][br]infiniteList = [1..][br]--==================[br]ghci>take 1000 infiniteList[br][/color][/b]のように1000まで取り出すときに初めて評価する、[b][color=#0000ff]のろい評価、遅延Lazy評価[/color][/b]という機構がある。[br]フィボナッチ数列も遅延評価で作れる。[br]なお[b]zipwith[/b]は他のよくある関数の表示でかくと、[b]zipwith(2項演算、リスト1,リスト2)[/b]となり、[br]リスト1,リスト2をzipしてリストを作るときに、[br]タプルのリストを作るのではなく2項演算をした結果のリストを作るということだ。[br]また、[b]tail リスト[/b]は、リストの2番目を先頭にしたリストのことだね。[br]だから、1個ずらして+をしたリストを続けて作ることになるね。[br]でも、実行時に評価するし、実行しないときは終了の位置は関係ない。[br]takeするときだけ実行するからだ。[br][color=#0000ff][b]--[Haskell]============[br]fibo :: [Integer][br]fibo = 1 : 1 : zipWith (+) fibo (tail fibo)[br][/b][b]--==================[br][/b][b]ghci> take 100 fibo[br][/b][/color][1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,433494437,701408733,1134903170,1836311903,2971215073,4807526976,7778742049,12586269025,20365011074,32951280099,53316291173,86267571272,139583862445,225851433717,365435296162,591286729879,956722026041,1548008755920,2504730781961,4052739537881,6557470319842,10610209857723,17167680177565,27777890035288,44945570212853,72723460248141,117669030460994,190392490709135,308061521170129,498454011879264,806515533049393,1304969544928657,2111485077978050,3416454622906707,5527939700884757,8944394323791464,14472334024676221,23416728348467685,37889062373143906,61305790721611591,99194853094755497,160500643816367088,259695496911122585,420196140727489673,679891637638612258,1100087778366101931,1779979416004714189,2880067194370816120,4660046610375530309,7540113804746346429,12200160415121876738,19740274219868223167,31940434634990099905,51680708854858323072,83621143489848422977,135301852344706746049,218922995834555169026,354224848179261915075][br][br]遅延評価を使うと、エラトステネスのふるいsieveの考え方が[br]そのままコードになる。[br]素数は2から始まるので2以上の整数リスト[2..]に[b]ふるいsieveにかける[/b]。その結果が素数たちprimesだ。[br]そこで、ふるいsieve(先頭p: 残りxs)は、pのあとは、xsのうち数pで割り割り切れないものを残す。[br][color=#0000ff][b]--[Haskell]============[br]primes :: [Integer][br]primes = sieve [2..][br] where[br] sieve (p:xs) = p : sieve (filter ((/=0) . (`mod` p)) xs)[br]--==================[br][/b][/color]ghci> take 100 primes[br][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,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541][br][color=#9900ff][b][u][size=150]質問:この遅延評価の考え方をpythonやjuliaでも使えますか。[br][/size][/u][/b][/color][br]普通にyieldとnextのペアで実現できます。[br][b]whileの無限ループの関数を作り、[br]return の代わりにyieldにして、戻り値を表します。[br][/b]もどった値を入れた変数にnext()をすることで、必要な回数だけ無限関数を有限回数で利用するという[br]理屈です。[br]while脱出型ではないですが、while停止型です。[br][color=#ff0000][b][u][size=150]pythonでもwhile機構を使わないと無限を表すことができないということでした。[br][/size][/u][/b][/color][br][IN]Python[br]#==============[br]def fibo():[br] a, b = 1, 1[br] [b] while True:[br] yield a[br][/b] a, b = b, a + b[br][b]f = fibo()[br][/b]for i in range(1,101):[br] print([b]next(f)[/b],end=",")[br]#==============[br][OUT][br]1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986,102334155,165580141,267914296,433494437,701408733,1134903170,1836311903,2971215073,4807526976,7778742049,12586269025,20365011074,32951280099,53316291173,86267571272,139583862445,225851433717,365435296162,591286729879,956722026041,1548008755920,2504730781961,4052739537881,6557470319842,10610209857723,17167680177565,27777890035288,44945570212853,72723460248141,117669030460994,190392490709135,308061521170129,498454011879264,806515533049393,1304969544928657,2111485077978050,3416454622906707,5527939700884757,8944394323791464,14472334024676221,23416728348467685,37889062373143906,61305790721611591,99194853094755497,160500643816367088,259695496911122585,420196140727489673,679891637638612258,1100087778366101931,1779979416004714189,2880067194370816120,4660046610375530309,7540113804746346429,12200160415121876738,19740274219868223167,31940434634990099905,51680708854858323072,83621143489848422977,135301852344706746049,218922995834555169026,354224848179261915075,[br][br]juliaにも「すぐに実行しないイテレータ」を作るしくみgenerator()とyield文があるのですが、[br]有限範囲で作ってから取り出すしくみなので、forを回したりメモ化の方が簡単です。[br]いろいろお膳立てすると無限と遅延が両立できるようです。