Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F#返回定义为构造函数数的输入大小_F# - Fatal编程技术网

F#返回定义为构造函数数的输入大小

F#返回定义为构造函数数的输入大小,f#,F#,这里是初学者f#程序员 所以基本上我完全迷路了。在过去的一个小时里,我一直盯着这个问题,甚至不知道如何设置let论证的第一行。这个问题要求使用模式匹配定义一个递归函数size:expr->int,该函数返回其输入表达式的大小,该大小被定义为表达式中expr类型的构造函数数 这是递归函数: size : expr -> int 以下是施工人员: type oper = Neg | Not | Add | Mul | Sub | Less | Eq | And type expr =

这里是初学者f#程序员

所以基本上我完全迷路了。在过去的一个小时里,我一直盯着这个问题,甚至不知道如何设置let论证的第一行。这个问题要求使用模式匹配定义一个递归函数size:expr->int,该函数返回其输入表达式的大小,该大小被定义为表达式中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