【发布时间】:2020-08-02 12:16:06
【问题描述】:
我正在尝试使用 monad 编写代码。难道我做错了什么? 我不明白为什么会出错。 “错误:此表达式的类型为 (expr -> 'a) -> 'a 但是需要一个 expr 类型的表达式”。 此错误出现在测试用例中。当我不使用单子时,它似乎工作正常。这是错误的使用方式吗?
type var = X | Y | Z;;
type expr = N of int
| V of var
| Add of expr * expr
| Mul of expr * expr;;
let add a b =
match (a, b) with
| ((N 0), y) -> y
| (x, (N 0)) -> x
| ((N x), (N y)) -> N (x + y)
| _ -> Add (a, b)
let mul a b =
match (a, b) with
| ((N 0), y) -> N 0
| ((N 1), y) -> y
| (x, (N 0)) -> N 0
| (x, (N 1)) -> x
| ((N x), (N y)) -> N (x * y)
| _ -> Mul (a, b)
let id x = x
module Cont = struct
let ret x = fun k -> k x
let (>>=) m f = fun k -> m (fun x -> (f x) k)
end
let rec deriv expr var =
let open Cont in
match expr with
| N x -> ret (N 0)
| V v -> if v = var then ret (N 1) else id ret (N 0)
| Add (a, b) -> deriv a var >>= fun x ->
deriv b var >>= fun y ->
ret (add x y)
| Mul (a, b) -> deriv b var >>= fun x ->
deriv a var >>= fun y ->
ret (add (mul a x)(mul b y))
| _ -> assert false
let rec to_str expr =
let open Printf in
let open Cont in
let var_to_str = function
X -> "x" | Y -> "y" | Z -> "z" | _ -> assert false in
match expr with
| N a -> ret (sprintf "%d" a)
| V v -> ret (var_to_str v)
| Add (a, b) -> to_str a >>= fun x -> to_str b
>>= fun y ->
ret (sprintf "(%s + %s)" x y)
| Mul (a, b) -> to_str a >>= fun x -> to_str b
>>= fun y ->
ret (sprintf "%s * %s" x y)
| _ -> assert false
(*test cases*)
let a = add (V X) (N 3)
let _ = to_str a (* "(x + 3)" *)
let _ = to_str (deriv a X) (* "1" *)
let _ = to_str (deriv a Y) (* "0" *)
let b = add (mul (N 2) (V X)) (mul (V Y) (N 3))
let _ = to_str b (* "(2 * x + y * 3)" *)
let _ = to_str (deriv b X) (* "2" *)
let _ = to_str (deriv b Y) (* "3" *)
let c = mul (mul (V X) (V Y)) (add (V X) (N 3))
let _ = to_str c (* "x * y * (x + 3)" *)
let _ = to_str (deriv c X) (* "(x * y + y * (x + 3))" *)
let _ = to_str (deriv c Y) (* "x * (x + 3)" *)
【问题讨论】:
标签: recursion functional-programming ocaml monads