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

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

新規登録して質問してみよう
ただいま回答率
85.48%
関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

関数型プログラミング

関数型プログラミングとは、関数を用いて演算子を構築し、算出し、コンピュータプログラムを構成する枠組みです。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

OCaml

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

Q&A

解決済

1回答

978閲覧

内部表現から計算式の結果を求める

grape_ll

総合スコア83

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

関数型プログラミング

関数型プログラミングとは、関数を用いて演算子を構築し、算出し、コンピュータプログラムを構成する枠組みです。

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

OCaml

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

0グッド

0クリップ

投稿2021/06/02 11:25

編集2021/06/05 02:45

###実現したいこと
変数の値のリストと,内部表現にによる式を与え,その計算式の値を求める.
この値を求める関数をevalとする.
(例)
eval [("x",4);("y",3)] (Mul(Mul(Var "x", Var "y"),Add(Var "x",Num 3)));;

  • : int = Some 84

###現状のコード

ocaml

1type exp = 2 | Num of int 3 | Var of string 4 | Add of exp * exp 5 | Mul of exp * exp;; 6 7let make_sum a1 a2 = Add (a1,a2);; 8 9let make_product m1 m2 = Mul (m1,m2);; 10 11let rec assoc x list = 12 match list with 13 |[] -> None 14 |(a,b)::t -> if a = x then Some b 15 else assoc x t;; 16 17let calc var = 18 match var with 19 | Add (Num x, Num y) -> x+y 20 | Mul (Num x, Num y) -> x*y;; 21 22let rec eval list var = 23 match var with 24 |Num n -> n 25 |Var x -> assoc (x list) 26 |Add (x, y) -> calc calc (eval (var));; 27 28let rec do_string_of_exp var judge = 29 match var with 30 | Num n -> string_of_int n 31 | Var x -> x 32 | Add (x, y) -> if judge=1 then "(" ^ do_string_of_exp (x) 0 ^ "+" ^ do_string_of_exp (y) 0 ^")" 33 else do_string_of_exp (x) 0 ^ "+" ^ do_string_of_exp (y) 0 34 | Mul (x, y) -> do_string_of_exp (x) 1 ^ "*" ^ do_string_of_exp (y) 1;; 35 36let string_of_exp var = 37 do_string_of_exp var 0;; 38 39 40

###以上のコードをuse "~.ml"を用いて使用しようとした結果

type exp = Num of int | Var of string | Add of exp * exp | Mul of exp * exp val make_sum : exp -> exp -> exp = <fun> val make_product : exp -> exp -> exp = <fun> val assoc : 'a -> ('a * 'b) list -> 'b option = <fun> File "ex3_3.ml", line 18, characters 4-84: 18 | ....match var with 19 | | Add (Num x, Num y) -> x+y 20 | | Mul (Num x, Num y) -> x*y.. Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: (Add (Num _, (Var _|Add (_, _)|Mul (_, _)))| Add ((Var _|Add (_, _)|Mul (_, _)), _)| Mul (Num _, (Var _|Add (_, _)|Mul (_, _)))| Mul ((Var _|Add (_, _)|Mul (_, _)), _)|Num _|Var _) val calc : exp -> int = <fun> File "ex3_3.ml", line 25, characters 21-22: 25 | |Var x -> assoc (x list) ^ Error: This expression has type string This is not a function; it cannot be applied.

###質問したい内容
Warningの分岐条件が足りてないというものは一度置いておいて.
25行目のxにを注意されていることが良くわかりません.
僕のなかでは,assocの第一引数は文字列であるとしているのですが,なぜここが関数でないからといってエラーが発生するのでしょうか.

assocという関数は連想リストを検索して,存在したらその値を,なかったらNoneを返すというものにしています.
assoc 4 [(2,"two"); (3,"three"); (5,"five")];;
これならばNoneが返る.

###追記
現状このようになっています.
しかしまだエラーが出てきます.コードの下にエラーを示します.

ocaml

1type exp = 2 | Num of int 3 | Var of string 4 | Add of exp * exp 5 | Mul of exp * exp;; 6 7let make_sum a1 a2 = Add (a1,a2);; 8 9let make_product m1 m2 = Mul (m1,m2);; 10 11let rec assoc x ls = 12 match ls with 13 |[] -> None 14 |(a,b)::t -> if a = x then Some b 15 else assoc x t;; 16 17let calc var = 18 match var with 19 | Add (Num x, Num y) -> Some (x+y) 20 | Mul (Num x, Num y) -> Some (x*y);; 21 22let rec eval ls var = 23 match var with 24 |Num n -> Some n 25 |Var x -> assoc x ls 26 |Add (x, y) -> calc Add ( eval ls Some x, eval ls Some y ) 27 |Mul (x, y) -> calc Mul ( eval ls Some x, eval ls Some y );;

####エラー

type exp = Num of int | Var of string | Add of exp * exp | Mul of exp * exp val make_sum : exp -> exp -> exp = <fun> val make_product : exp -> exp -> exp = <fun> val assoc : 'a -> ('a * 'b) list -> 'b option = <fun> File "ex3_3.ml", line 18, characters 4-98: 18 | ....match var with 19 | | Add (Num x, Num y) -> Some (x+y) 20 | | Mul (Num x, Num y) -> Some (x*y).. Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: (Add (Num _, (Var _|Add (_, _)|Mul (_, _)))| Add ((Var _|Add (_, _)|Mul (_, _)), _)| Mul (Num _, (Var _|Add (_, _)|Mul (_, _)))| Mul ((Var _|Add (_, _)|Mul (_, _)), _)|Num _|Var _) val calc : exp -> int option = <fun> File "ex3_3.ml", line 26, characters 19-23: 26 | |Add (x, y) -> calc Add ( eval ls Some x, eval ls Some y ) ^^^^ Error: This function has type exp -> int option It is applied to too many arguments; maybe you forgot a `;'.

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

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

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

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

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

guest

回答1

0

ベストアンサー

(x list)とカッコがついているのでxが関数と推論されているのでは?


assoc x listにすると型が合わないと怒られる問題について:

ocaml

1type exp = 2 | Num of int 3 | Var of string 4 | Add of exp * exp 5 | Mul of exp * exp;; 6 7//... 8 9let rec eval list var = 10 match var with 11 |Num n -> n 12 |Var x -> assoc x list 13 |Add (x, y) -> calc calc (eval (var));; 14

とあるので evalの最初のパターンマッチの返り値nintですが、
その次の返り値 assoc x listの型は'a optionと何かしらのオプション型なので
型が全然合ってません。

問題文を見ると、

eval [("x",4);("y",3)] (Mul(Mul(Var "x", Var "y"),Add(Var "x",Num 3)));;

: int = Some 84

なのですから evalの返り値はint optionとすべきですね。
つまり|Num n -> nの時点でもう型が違います。

とりあえず(全部消してイチから)全部の関数に型を明示して書いてはどうでしょう。


文法が似ているF#で書いてみました

F#

1open System 2 3 4type Exp = 5 | Num of int 6 | Var of string 7 | Add of Exp * Exp 8 | Mul of Exp * Exp 9 10 11// let hoge = Mul(Num 3, Var "x") // OK 12 13type VarValuePair = string * int 14 15 16let rec assoc (name : string) (pairs : VarValuePair list) : int option = 17 match pairs with 18 | [] -> None 19 | (var, value)::t -> 20 if var = name then Some value 21 else assoc name t 22 23let rec eval (pairs : VarValuePair list) (exp : Exp): int option = 24 match exp with 25 | Num x -> Some x 26 | Var var -> assoc var pairs 27 | Add (x, y) -> 28 let x = (eval pairs x) 29 let y = (eval pairs y) 30 match (x, y) with 31 | (Some x, Some y) -> Some (x+y) 32 | _ -> None 33 | Mul (x, y) -> 34 let x = (eval pairs x) 35 let y = (eval pairs y) 36 match (x, y) with 37 | (Some x, Some y) -> Some (x*y) 38 | _ -> None 39 40 41[<EntryPoint>] 42let main argv = 43 44 let result = eval [("x",4); ("y",3)] (Mul(Mul(Var "x", Var "y"),Add(Var "x",Num 3))) 45 printfn "%A" result 46 0 // return an integer exit code 47 48

投稿2021/06/02 21:11

編集2021/06/03 08:01
ozwk

総合スコア13521

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

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

grape_ll

2021/06/03 06:46

括弧がつくと関数扱いを受けるのはなぜなのか,解説していただくことは出来ますでしょうか. また,()を外してみたところ. # #use "ex3_3.ml";; type exp = Num of int | Var of string | Add of exp * exp | Mul of exp * exp val make_sum : exp -> exp -> exp = <fun> val make_product : exp -> exp -> exp = <fun> val assoc : 'a -> ('a * 'b) list -> 'b option = <fun> File "ex3_3.ml", line 18, characters 4-84: 18 | ....match var with 19 | | Add (Num x, Num y) -> x+y 20 | | Mul (Num x, Num y) -> x*y.. Warning 8: this pattern-matching is not exhaustive. Here is an example of a case that is not matched: (Add (Num _, (Var _|Add (_, _)|Mul (_, _)))| Add ((Var _|Add (_, _)|Mul (_, _)), _)| Mul (Num _, (Var _|Add (_, _)|Mul (_, _)))| Mul ((Var _|Add (_, _)|Mul (_, _)), _)|Num _|Var _) val calc : exp -> int = <fun> File "ex3_3.ml", line 25, characters 14-26: 25 | |Var x -> assoc x list ^^^^^^^^^^^^ Error: This expression has type 'a option but an expression was expected of type int このように別のエラーになってしまうようです. 文字列で検索を掛けたいのでint型に治したくはないのですが,どのようにすればよいでしょうか.
ozwk

2021/06/03 07:02 編集

assoc (x list) と書いたら、 let y = x list assoc y と同等の意味になります x list と書いたからには x に引数 list を渡していることになるので すなわちxは関数であるはず。となります。
grape_ll

2021/06/05 02:58

関数の引数に括弧をつけるのが自然な流れだと感じでいるのつけてしまったのですが,ocamlでは意味が変わってしまうのですね.ありがとうございます. 型の明示をしてみたところ,うまく明示できていないのか,他のところで問題が起き始めてしまったので,断念してしまったのですが,教えていただいたF#を拙いながらも読んで参考にさせていただきながら自分のコードを変更しました.質問内容の追記に載せていただきます. しかし,引数の数がおかしいというエラーが生じてしまいました. Add()一つしか渡していないように思うのですが,なぜ数がおかしいと言われているのでしょうか.
ozwk

2021/06/05 05:15

calc Add (...)は calc にAdd と (...)を渡していることになります calc (Add (...))です
grape_ll

2021/06/05 05:31

このAddはAdd of exp * exp のものだと私は想定していて,このときはAdd (...)で1つのものになると思っていたのですが,なぜそう受け取られないのか,理由などはございますでしょうか. また,calc (Add (..))としたところ, 26 | |Add (x, y) -> calc (Add ( eval ls Some x, eval ls Some y ))      ^^^^ Error: This function has type (string * int) list -> exp -> int option It is applied to too many arguments; maybe you forgot a `;'. となり,これも同じ理由だと考え, calc (Add ( eval ls (Some x), eval ls (Some y) )) としたのですが 26 | |Add (x, y) -> calc (Add ( eval ls (Some x), eval ls (Some y) ))      ^^^^ Error: This variant expression is expected to have type exp The constructor Some does not belong to type exp となってしまいました. Someは何が入ってもいいというような認識でいたのですが,type expに属していないといわれているので, |Add (x, y) -> のあとに16通りのx, yのマッチングを記述しなくてはいけないのでしょうか.
ozwk

2021/06/05 06:08 編集

> 型の明示をしてみたところ,うまく明示できていないのか,他のところで問題が起き始めてしまった 型を明示して起こる問題は、型を明示しなかったらよりわかりにくい形で現れるだけです。 書きましょう。 さてともかく > Add (x, y) -> calc (Add ( eval ls (Some x), eval ls (Some y) )) Add of exp * expですから xとyはexpですね。 eval ls (Some x)は lsが多分(string * int)で(Some x)は exp optionですね。 一方eval は 型が明示してありませんが (string * int) list -> exp -> int optionでしょう。 となると型があってませんね。expを渡すべきところをexp optionを渡しています
grape_ll

2021/06/05 06:58

exp とexp optionの違いが良くわかっていない状態でして, exp optionはexpの中身でNumやvalのことでしょうか. 直すために,Addがexp*expならば,evalの引数にそのままxを入れて |Add (x, y) -> calc (Add ( eval ls x, eval ls y )) のようにすればよいのではないかと思ったのですが. 26 | |Add (x, y) -> calc (Add ( eval ls x, eval ls y ))      ^^^^^^ Error: This expression has type int option but an expression was expected of type exp となってしまい,確かにeval関数はint optionを返しているなというのは読み取れるのですが,そうなるとevalを再帰的に用いてAdd()を見ていくことが出来ないということになってしまうように思われます. なにか対象法等はありますでしょうか.
grape_ll

2021/06/05 07:13

let add (Some x, Some y) = Some (x + y);; let mul (Some x, Some y) = Some (x * y);; let rec eval ls var = match var with |Num n -> Some n |Var x -> assoc x ls |Add (x, y) -> add ( eval ls x, eval ls y ) |Mul (x, y) -> mul ( eval ls x, eval ls y );; このようにしましたら # eval [("x",4);("y",3)] (Mul(Mul(Var "x", Var "y"),Add(Var "x",Num 3)));; - : int option = Some 84 このようになったのですが,これは力業すぎますでしょうか.
ozwk

2021/06/05 07:32

> exp とexp optionの違いが良くわかっていない状態でして, そこからですか... 'a optionは Some of 'a | Noneのことです。 > 確かにeval関数はint optionを返しているなというのは読み取れるのですが,そうなるとevalを再帰的に用いてAdd()を見ていくことが出来ないということになってしまうように思われます. 「Add(x,y)をevalする際に、 x(またはy)のevalがNoneだったらどうあるべきか」を考えてください。 Add(x, y)のevalは x, y のeval結果が両方ともSomeである場合はSome (和)、そうでなければNoneとするのが適当でしょう。
ozwk

2021/06/05 07:42

> 力業すぎますでしょうか Warningでません?
grape_ll

2021/06/05 11:17 編集

optionについて,定義的に理解することは出来たような気がします.ありがとうございます. Noneに対応するため. let add (Some x, Some y) = if x = None then None else if y = None then None else Some (x + y);; としてみたのですが,こうすると 25 | else Some (x + y);;    ^ Error: This expression has type 'a option but an expression was expected of type int となってしまいます,なせ条件分岐を付けただけでintであると期待されてしまうのでしょうか. warningは出ますが,計算自体は問題ないようです リストにない文字を用いるとexeptionを出してしまうのがocamlらしいものではないと思いますが,それいがは特に問題のある計算例を見つけられていません.
ozwk

2021/06/05 11:26

> リストにない文字を用いるとexeptionを出してしまう はい、それが問題です。 add がSome x, Some yで受けてるのでNone来たらどうすんの?ってことです。 add をSome xで受けずにxで受けるようにして中でSome Noneを場合分けしてください
grape_ll

2021/06/05 11:42

let add (x, y) = match x with |None -> None |Some x -> match y with |None -> None |Some y -> Some (x + y);; let mul (x, y) = match x with |None -> None |Some x -> match y with |None -> None |Some y -> Some (x + y);; let rec eval ls var = match var with |Num n -> Some n |Var x -> assoc x ls |Add (x, y) -> add ( eval ls x, eval ls y ) |Mul (x, y) -> mul ( eval ls x, eval ls y );; のようにしたら # eval [("x",2);("y",3)] (Mul(Mul(Add(Var "x", Var "z"), Var "y"),Add(Var "x",Num 3)));; - : int option = None となって望んでいるような形で帰ってきました.
ozwk

2021/06/05 11:49

お疲れ様でした
grape_ll

2021/06/05 11:59

とても丁寧に手助けしていただきありがとうございました.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問