見出し画像

関数型プログラミングの初級問題-25問目- 「ランダムな並び替え」

 プログラミング初心者が挑戦する関数型プログラミングによるリスト操作の練習問題の25問目です。問題は、OCaml公式ページのものを使いました。
 内容は、問題と答案です。答案の作成時間は、約1分でした。

問題25.

 無作為にリストの要素を並べ替える関数permurationを書け。

※ 例えば、permuration ["a"; "b"; "c"]は["a"; "c"; "b"]になります。

答案

本問の解き方

 リストにおけるn番目の要素を抜き出す関数extractは、問題23.の答案で作りました。
 また、リストのm番目の位置に要素を挿入する関数insert_atは、問題21.の答案で作成しました。
 
 したがって、これらの関数と乱数とを組み合わせれば並べ替え関数permurationとなります。
 具体的には、extractでn番目の要素をリストから抜き出し、その抜き出した要素をinsert_atによりm番目に挿入します。このとき、nとmを乱数とすることで要素が無作為に並べ替えられます。
 以上の操作を適当な回数だけ繰り返します。本答案では、繰り返し回数をリストの長さとしました。

コード

external rnd_initialize : unit->unit = "rnd_initialize"
external rnd : int->int = "rnd"
external rnd_finalize : unit->unit = "rnd_finalize"

let permuration lisuto =
 let rec len = function [] -> 0 | head::tail -> 1+len tail in
 let rec split i = function [] -> ([], []) | head::tail ->
 if i < 1 then ([], head::tail)
 else let (zenhan, kohan) = split (i-1) tail in (head::zenhan, kohan) in
 let extract lisuto =
 let (zenhan, kohan) = split (rnd (len lisuto)) lisuto in
 match kohan with
  | [] -> raise (Failure "extract")
  | head::tail -> (head, zenhan@tail) in
 let insert_at youso n lisuto =
  let rec split i = function [] -> ([], []) | head::tail ->
   if i < 1 then ([], head::tail)
   else let (zenhan, kohan) = split (i-1) tail in
  (head::zenhan, kohan) in
 let (zenhan, kohan) = split n lisuto in zenhan@youso::kohan in
 let rec swap n lisuto =
  if n < 1 then lisuto
  else let (youso, nokori) = extract lisuto in
 swap (n-1) (insert_at youso (rnd (len lisuto)) nokori) in
 
swap (len lisuto) lisuto

 今回の答案で実質的に書いたコードは関数swapだけです。

感想

 率直に言ってわけがわかりません。高々30行ほどのコードなのに読み難くくて仕方がありません。関数の区切位置がよく分からないし、変数の有効範囲もよく分かりません。

 練習問題を解くよりもさきに、コーディングの作法を学ぶべきかもしれません。面倒くさいからやりませんが…

 それとも内部関数にしなければ少しは読み易くなるかも知れません。

 次回は、第26問です。親愛なる読者様は、お前が読むタイトルは詐欺かもしれないのです。なぜなら副作用のためです。安全は、URLをクリックして確認します。ご挨拶、記事著者。

古往今来得ざれば即ち書き得れば即ち飽くは筆の常也。と云うわけで御座います、この浅ましき乞食めに何卒皆々様のご慈悲をお願い致します。