質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

OCaml

OCaml(オーキャムル)は、フランスのINRIAが開発した関数型言語MLの一種で、 最新の言語理論の成果が取り入れられているプログラミング言語です。

Q&A

解決済

1回答

1820閲覧

[初心者]else文でなぜrestが出てくるのかわからないです Ocaml

ryuuabis

総合スコア24

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

データ構造

データ構造とは、データの集まりをコンピュータの中で効果的に扱うために、一定の形式に系統立てて格納する形式を指します。(配列/連想配列/木構造など)

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

OCaml

OCaml(オーキャムル)は、フランスのINRIAが開発した関数型言語MLの一種で、 最新の言語理論の成果が取り入れられているプログラミング言語です。

0グッド

0クリップ

投稿2021/08/23 10:44

編集2021/08/30 01:52

○前提・実現したいこと
プログラミングの基礎という初心者向けのOcamlの教材でメトロネットワークを作る問題をしていたのですが理解できないところがあります。

駅間リストのデータから情報を取り出す関数 get_ekikan_kyori を作り、駅名を二つ受け取ってその間の距離を返すというものです。

get_ekikan_kyori "茗荷谷" "新大塚" global_ekikan_list

で 1.2 を返すなどです。 直接繋がっていない時にはinfinityを返します。

type ekikan_t = { kiten : string; (* 起点 *) shuten : string; (* 終点 *) keiyu : string; (* 経由路線名 *) kyori : float; (* 距離 *) jikan : int; (* 所要時間 *) } let global_ekikan_list = [ {kiten="代々木上原"; shuten="代々木公園"; keiyu="千代田線"; kyori=1.0; jikan=2}; {kiten="代々木公園"; shuten="明治神宮前"; keiyu="千代田線"; kyori=1.2; jikan=2}; {kiten="明治神宮前"; shuten="表参道"; keiyu="千代田線"; kyori=0.9; jikan=2}; {kiten="表参道"; shuten="乃木坂"; keiyu="千代田線"; kyori=1.4; jikan=3}; {kiten="乃木坂"; shuten="赤坂"; keiyu="千代田線"; kyori=1.1; jikan=2}; {kiten="赤坂"; shuten="国会議事堂前"; keiyu="千代田線"; kyori=0.8; jikan=1}; {kiten="国会議事堂前"; shuten="霞ヶ関"; keiyu="千代田線"; kyori=0.7; jikan=1}; let rec get_ekikan_kyori eki1 eki2 lst = match lst with [] -> infinity | {kiten = k; shuten = s; keiyu = y; kyori = r; jikan = j} :: rest -> if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k) then r else get_ekikan_kyori eki1 eki2 rest (* テスト *) let test1 = get_ekikan_kyori "茗荷谷" "新大塚" global_ekikan_list = 1.2 let test2 = get_ekikan_kyori "茗荷谷" "池袋" global_ekikan_list = infinity let test3 = get_ekikan_kyori "東京" "大手町" global_ekikan_list = 0.6

パターンマッチを使うときは先頭のリストと残りのリストに分けてfirstとrestというパターン変数を使ってアクセスするらしいです。

片方の距離だけなので駅1が始点と終点でif (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k)、
then rで距離を返すのは分かるのですが、なぜelseでrestが出てくるのかがわからないです。
それとパターンマッチでfirstではなく{kiten = k; shuten = s; keiyu = y; kyori = r; jikan = j}を代わりに使ってる理由も教えていただきです。
そもそもなぜ、リストは、first(最初の要素) とrest(その残りの要素)に分けているのでしょうか?

どなたかご存知の方教えていただけたら助かります、、、

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

パターンマッチを使うときは先頭のリストと残りのリストに分けてfirstとrestというパターン変数を使ってアクセスするらしいです。

なんだか「そういう決まり」というように思っていそうですが、別にそんなことはないです。

なぜelseでrestが出てくるのかがわからないです。

リストの先頭が調べたい駅間データなのかを判定して、
そうだったらその駅間データの距離を返して、
違ったらリストの残りに対して同じ処理をする、という作りのプログラムだからです。

それとパターンマッチでfirstではなく{kiten = k; shuten = s; keiyu = y; kyori = r; jikan = j}を代わりに使ってる理由も教えていただきです。

別にfirst::restと書いてもいいです。
その場合eki1=first.kitenなどとなるだけです。

そもそもなぜ、リストは、first(最初の要素) とrest(その残りの要素)に分けているのでしょうか?

リストの先頭が調べたい駅間データなのかを判定して、
そうだったらその駅間データの距離を返して、
違ったらリストの残りに対して同じ処理をする、という作りのプログラムだからです。


コメントに対する追記

先頭の要素と残りの要素というのは先頭がkiten="代々木上原"; shuten="代々木公園"; keiyu="千代田線"; kyori=1.0; jikan=2};で、残りの要素が{kiten="代々木公園"; shuten="明治神宮前"; keiyu="千代田線"; kyori=1.2; jikan=2};からそれ以降全部ということなんでしょうか?

global_ekikan_listに対して言えばそうです。

再帰関数は処理が出来上がっている前提で使う関数?だと思うのですが

何を言っているのかわかりません。

なぜ then r のところにはget_ekikan_kyori を使っていなくelseの方だけ使っているのでしょうか?

使う必要がどこにあるのです?

if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k) は何をしているのか教えていただけないでしょうか?

(eki1 = k && eki2 = s) || (eki1 = s && eki2 = k)かどうかを判定しています。


リストlstxがあるかないかを返す関数isExistを似たようなアルゴリズムで書いてみました。

Ocaml

1let rec isExist x lst = match lst with 2 [] -> false 3 | first :: rest -> 4 if x = first then true 5 else isExist x rest; 6 7isExist 5 [1;2;3;4;5]; (* true *) 8isExist 5 [1;2]; (* false *)

投稿2021/08/30 02:10

編集2021/08/31 06:26
ozwk

総合スコア13528

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ryuuabis

2021/08/31 03:15

返信ありがとうございます。データを取り出すプログラムということなんですね。。 すみません、先頭の要素と残りの要素というのは先頭がkiten="代々木上原"; shuten="代々木公園"; keiyu="千代田線"; kyori=1.0; jikan=2};で、残りの要素が{kiten="代々木公園"; shuten="明治神宮前"; keiyu="千代田線"; kyori=1.2; jikan=2};からそれ以降全部ということなんでしょうか? それと再帰関数は処理が出来上がっている前提で使う関数?だと思うのですがなぜ then r のところにはget_ekikan_kyori を使っていなくelseの方だけ使っているのでしょうか? すみませんそれと if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k) は何をしているのか教えていただけないでしょうか? 沢山の追加質問すみません、、 教えていただけたら助かります。。
ozwk

2021/08/31 04:03

追記しました
ryuuabis

2021/08/31 05:55

分かりにくい質問ですみません。。 first::restの説明分かりました、ありがとうございます。 再帰関数ということはget_ekikan_kyoriという関数の処理の中でまたget_ekikan_kyoriという関数を使える(elseで使っているみたいに)と思うのですが、if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k)を判定してその通りだったらthenでget_ekikan_kyori eki1 eki2みたいに使うべきじゃないのでしょうか。 get_ekikan_kyori自体がリストの先頭が調べたい駅間データなのかを判定して、 そうだったらその駅間データの距離を返して、違ったらリストの残りに対して同じ処理をする、という作りのプログラムだとしたら、なぜにif (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k)を判定して違った場合のelseで使っているのでしょうか。 判定して違ったらinfinityだったり空リストを返すものじゃないのでしょうか、、?
ryuuabis

2021/08/31 06:03 編集

正解はこうなっていますが、 let rec get_ekikan_kyori eki1 eki2 lst = match lst with [] -> infinity | {kiten = k; shuten = s; keiyu = y; kyori = r; jikan = j} :: rest -> if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k) then r else get_ekikan_kyori eki1 eki2 rest こうか、 let rec get_ekikan_kyori eki1 eki2 lst = match lst with [] -> infinity | {kiten = k; shuten = s; keiyu = y; kyori = r; jikan = j} :: rest -> if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k) then r else r rest こうになるイメージなのですが let rec get_ekikan_kyori eki1 eki2 lst = match lst with [] -> infinity | {kiten = k; shuten = s; keiyu = y; kyori = r; jikan = j} :: rest -> if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k) then get_ekikan_kyori eki1 eki2 else get_ekikan_kyori eki1 eki2 rest なぜ一番上のようなプログラムになっているのでしょうか、、
ozwk

2021/08/31 06:17 編集

> get_ekikan_kyori自体がリストの先頭が調べたい駅間データなのかを判定して、 そうだったらその駅間データの距離を返して、違ったらリストの残りに対して同じ処理をする、という作りのプログラムだとしたら、なぜにif (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k)を判定して違った場合のelseで使っているのでしょうか。 判定して違ったらinfinityだったり空リストを返すものじゃないのでしょうか、、? 「違ったらリストの残りに対して同じ処理をする」のですから 「違ったらinfinityだったり空リストを返す」のではおかしいでしょう。
ozwk

2021/08/31 06:29

> 再帰関数ということはget_ekikan_kyoriという関数の処理の中でまたget_ekikan_kyoriという関数を使える(elseで使っているみたいに)と思うのですが、 はい。使えます。 > if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k)を判定してその通りだったらthenでget_ekikan_kyori eki1 eki2みたいに使うべきじゃないのでしょうか。 なぜ? if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k) は先頭要素が目的のものだったらthenですよ? ひょっとして逆だと思ってます?
ozwk

2021/08/31 06:37 編集

> else r rest r は float で restはekikan_t listですから r rest は floatという関数でないものにekikan_t listを渡そうとしていて意味わからんでしょう。 > get_ekikan_kyori eki1 eki2 get_ekikan_kyori が返したいのはfloatですが その返り値をget_ekikan_kyori eki1 eki2としたら ekikan_t list-> floatで型が合ってません。
ryuuabis

2021/09/01 04:54

if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k) で判定して thenはfirst 、 else はrest についての処理を書くという認識でよろしいでしょうか? 関数の中の処理に使える再帰関数のget_ekikan_kyoriはfirstのthenでは使えず、 restのelstしか使えないということでしょうか? 同じ型の関数しか渡せないということでしょうか、 ということは参考に書いていただいたアルゴリズムの、else isExist x rest; は 自動的にrestなど全てbool型に変換されているということでしょうか?
ozwk

2021/09/01 05:07

> if (eki1 = k && eki2 = s) || (eki1 = s && eki2 = k) で判定して thenはfirst 、 else はrest についての処理を書くという認識でよろしいでしょうか? なんだかそう書かなければいけないみたいな言い方が気になりますが、 とりあえず今回はそう書いているということです。 > 関数の中の処理に使える再帰関数のget_ekikan_kyoriはfirstのthenでは使えず、 restのelstしか使えないということでしょうか? 別に文法上は使っても問題ありません。 > 同じ型の関数しか渡せないということでしょうか、 ということは参考に書いていただいたアルゴリズムの、else isExist x rest; は 自動的にrestなど全てbool型に変換されているということでしょうか? いいえ、変換などしていません。 isExistは 'a -> 'a list -> bool 型ですから (isExist x rest)はbool型です
ozwk

2021/09/01 05:17

isExistに関して説明すれば 「リストからとある値があるかどうかを判定する操作」とは リストが空であれば、返り値は「なかった」となる。 リストが空でなければ、返り値は、 先頭要素が「とある値」であれば、「あった」となる。 そうでなければ残りのリストに対して「リストからとある値があるかどうかを判定する操作」を行った結果となる。 まずプログラム抜きにこの手順で探せることを理解しないといけません。
ryuuabis

2021/09/01 06:00

そうでなければ残りのリストに対して「リストからとある値があるかどうかを判定する操作」を行った結果となる。とは、それ以前のリストが空であれば、返り値は「なかった」となる。 リストが空でなければ、返り値は、 先頭要素が「とある値」であれば、「あった」となる。の処理を繰り返すということなんですね。なるほどです。。 すみません、まずプログラム抜きにこの手順で探せることを理解しないといけません。 、とは関数のisExistを使わずに探したりできるという意味でしょうか? すみませんそれと、isExistは 'a -> 'a list -> bool 型ですから (isExist x rest)はbool型 の'a -> 'a list -> bool 型は処理の結果の一連の流れの型みたいなことでしょうか。型がどんどん変わっていっているということなんでしょうか、 それともaはx, a listはlist , 最後のboolはfalseを書いているからOcamlが自動的にboolと判断して最終的にbool型と自分で理解していくということでしょうか?
ozwk

2021/09/01 06:41

> プログラム抜き 純粋なアルゴリズムの話です。例えば人間に指示してやらせるなど > すみませんそれと、isExistは 'a -> 'a list -> bool 型ですから ... `aを受け取って`a listを受け取ってboolを返す関数型という意味です (正確には`aを受け取って「`a listを受け取ってboolを返す関数」を返す関数型) なんの教材を使っているかはわかりませんが、基本的なことなので多分最初の方に出てくるはず... Ocamlは型をあまり明示しないから出てこなくても不思議ではないですが。
ozwk

2021/09/01 06:49

「プログラミングの基礎」という本なのですね。 目次を見た限り4章ぐらいからやり直したほうが良さそうです
ryuuabis

2021/09/01 11:14

なるほど、型の最後は返すという意味なのですね。 そうですね、理解できてないので復習とアルゴリズム自体の勉強もしたいと思います。。 ここまで分かりやすく説明していただきとても助かりました、、! ありがとうございましたm(__)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問