F#返回定义为构造函数数的输入大小
这里是初学者f#程序员 所以基本上我完全迷路了。在过去的一个小时里,我一直盯着这个问题,甚至不知道如何设置let论证的第一行。这个问题要求使用模式匹配定义一个递归函数size:expr->int,该函数返回其输入表达式的大小,该大小被定义为表达式中expr类型的构造函数数 这是递归函数:F#返回定义为构造函数数的输入大小,f#,F#,这里是初学者f#程序员 所以基本上我完全迷路了。在过去的一个小时里,我一直盯着这个问题,甚至不知道如何设置let论证的第一行。这个问题要求使用模式匹配定义一个递归函数size:expr->int,该函数返回其输入表达式的大小,该大小被定义为表达式中expr类型的构造函数数 这是递归函数: size : expr -> int 以下是施工人员: type oper = Neg | Not | Add | Mul | Sub | Less | Eq | And type expr =
size : expr -> int
以下是施工人员:
type oper = Neg | Not | Add | Mul | Sub | Less | Eq | And
type expr =
| C of int
| Op1 of oper * expr
| Op2 of oper * expr * expr
| If of expr * expr * expr
比如说,
size(C 4)
将返回1
及
将返回6
建议后更新:正在进行
let rec size (e : expr) : int =
match e with
| C i -> 1
| Op1 (o, e1) -> size e1 + 1
| Op2 (o, e1, e2)-> size e2 + 1
| If (e1, e2, e3) -> size e3 + 1
我将总结您在评论中得到的提示,以便发现此问题的其他人可以看到答案,并且您能够解决问题:
oper
的参数;一个expr
类型的参数就足够了size
的递归函数时,您有时会陷入“好吧,我需要在这里调用我的size
函数……但既然我还没有编写它,我怎么知道它会返回什么?”最好的方法是假装您已经编写了函数,您已经知道它将返回什么,然后使用该函数。神奇的是,这一切都成功了:当您完成函数时,它调用的函数(本身)也完成了!结果很有趣。:-)let rec size (e : expr) : int =
match e with
| C i -> 1
| Op1 (o, e1) -> size e + 1
// Rest of function omitted
这给了您一个StackOverflowException,因为在Op1
匹配案例中调用size e
是一个无限递归循环。提示:从精神上追踪那个呼叫,并思考它将经历的步骤。它将根据Op1
检查e
,并第二次调用size e
。该调用将根据Op1
检查e
,并第三次调用size e
。那会结束吗?这些调用是否每次都会执行与以前的调用不同的操作,或者它们是否会“永远”循环,直到函数堆栈耗尽空间expr
变量的情况下,需要处理所有变量,而不仅仅是一个删除关于o的位应该与您想要的有关函数类型为
expr->int
,这意味着它应该接受一个expr
类型的参数,并返回一个int
。到目前为止,您已经定义了一个接受两个参数的函数,expr
和oper
。实际上,您不需要第二个参数。expr
类型携带运算符作为数据;如果您有一个expr
,则可以使用匹配模式获取其中的任何oper
值。也就是说,将thisExpr与| Op1(o,e)->……
匹配,现在您有了一个变量o
,它是操作内部的thisExpr
。一旦您开始编写函数,还有一个提示。在编写类似于size
的递归函数时,您有时会陷入“好的,我需要在这里调用我的size
函数……但是既然我还没有编写它,我怎么知道它会返回什么?”最好的方法是假装您已经编写了函数,您已经知道它将返回什么,然后使用该函数。也就是说,如果你有一个Op1
,你知道它的大小将是它所包含的expr
的大小,加上1。什么能告诉你它的大小?您正在编写的size
函数!提示:实际上,您并不需要一个看起来很好的计数器变量,但是:1)您不需要指定参数的类型,因为F#可以为您计算出来,2)您希望使用子表达式递归调用size
,而不是使用原始表达式再次调用它。换句话说,调用size(e)
将创建一个无限的递归循环。您需要在此处调用size(e1)
。
let rec size (e : expr) : int =
match e with
| C i -> 1
| Op1 (o, e1) -> size e + 1
// Rest of function omitted