見出し画像

関数型プログラミングの初級問題-17問目- (約0分)

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

問題17.

 リストを前後に分割する関数であって、所与の長さの前半部分と残りの後半部分とからなるタプルを返す関数splitを書け。
(所与の長さがリストの長さに満たない場合は、後半部分は空リストになります。)

※ 例えば、split ["1"; "2"; "3"; "4"; "5"] 2は(["1"; "2"], ["3"; "4"; "5"])になります。

答案

基本的な考え方

 関数型プログラミングによるリスト操作の基本的な流れは、以下の1から3になります。
  1. 引数のリストをheadとtailに分離する
  2. tailを引数として再帰呼び出すると共に、その返り値とheadを適当に組み合わせる
  3. 以上を引数のリストが停止条件に達するまで繰り返す

本問の解き方

 前問の分割関数とほぼ同じであり、n番目の要素が前半部分に含まれる点のみが異なります。
 そこで、停止条件をn <= 1からn < 1に変更し、これに併せて返り値をtailからリスト全体に変更します。

コード

OCaml

let rec split = fun lisuto n -> match lisuto with
 | [] -> ([], [])
 | head::tail -> if n < 1 then ([], lisuto) else let (kolisuto, nokori) = split tail (n-1) in (head::kolisuto, nokori)

Go

type Double struct {
 first []string
 second []string
}

func cons (result []string, head string, tail [] string) []string {
 if len (tail) == 0 {
  return append (result, head)
 } else {
  return cons (append (result, head), tail[0], tail[1:])
 }
}
func split (list []string, n int) Double {
 if len (list) == 0 {
  return Double {[]string{}, []string{}}
 } else {
  if n < 1 {
   return Double {[]string{}, list[:]}
  } else {
   double := split (list[1:], n-1)
   return Double {cons ([]string{}, list[0], double.first), double.second}
  }
 }
}

 Goは型変数を使えないので文字列のみの関数になってます。
 


感想

OCaml

 また、問題の順番が逆転しています。前問の答案の一部が、今回の答案になっています。
 ここまで出題順がおかしいのはおかしいので、解き方の方に問題があるのかもしれません。

Go

 物足りなかったので、Goに再挑戦しました。

Slice
 今回は、配列に拘りませんでした。どうもGoの配列はコンパイル時に長さが定まっている必要があるようです。これでは、リスト構造の構成物に使えません。
 そこで、sliceを使いました。無理に配列でがんばらずに、はじめから使えばよかったです。

タプル
 Goは複数の値を返すことができるのでタプルは必要ありませんが、OCamlに合わせて無理やり定義しました。

Goの印象
 コードを書いて感じたGoの印象は、必要最低限のコンパクトな設計を目指している、です。
 この設計思想は、自身の嗜好とも合い非常によいと思います。
 それだけに、想定外であろう関数型プログラミングを行うのは、何かもったいなく感じてしまいます。
 なので、「関数型プログラミングで」Goを使用するのは、今回で最後にしたいと思います。

 次回は、第18問です。Goの次はどの言語にするべきなのか?最も小遣いを稼げる可能性が高いのは…

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