2016-04-24 137 views
1

我试图在f#中使用两个数组创建一个计算器,一个存储数字,另一个存储运算符。我需要符号数组来模式匹配符号,并根据运算符从数组中获取前两个元素并执行操作并将新数字添加到第二个数组的头部。从数组中取出两个元素并添加它们,然后将它们添加回数组

open System 

[<EntryPoint>] 
let main argv = 
printfn "%A" argv 

let Add x y = x + y 
let Sub x y = x - y 
let Div x y = x * y 
let Mul x y = x/y 

printfn "1 > Calculator \n2 > Load from txt file" 

let chosenIn = Console.ReadLine(); 

//This is where I need to do the operation and after call the sum function 
//again until there's only one element left in the number array 
let rec sum num (numArray : int[]) sym (symArray : string[])() = 



let rec calc() = 
    printfn "Enter Sum" 
    let input = Console.ReadLine() 
    let intInput = input.Split() 
    let numArray = [|for num in intInput do 
         let v , vp = System.Int32.TryParse(num) 
         if v then yield vp|] 

    let symbolArray = [|for symbol in intInput do 
         match symbol with 
         | "+" -> yield symbol 
         | "-" -> yield symbol 
         | "/" -> yield symbol 
         | "*" -> yield symbol 
         | _ -> ignore 0|] 

    calc() 

match chosenIn with 
| "1" -> calc() 
| "2" -> printfn "File" 
| _ -> printfn "Invalid" 

0 // return an integer exit code 
+1

问题不明确,少数代码片段对澄清问题的可能性很少有帮助。当前代码接受“1 2 3 4”作为输入,就像接受“+ - /”或“1 2/+ 3 * *”一样。请澄清这些情况下的预期行为。 –

+0

其中一个主要问题是对于''',''和'*'签名是'int - > int - > int',但对于'/'它可以是'int - > int - > int ''或'int - > int - > float'这就是为什么如果你看看某些例子,你会看到'/'的答案。此外,输入应与操作符和操作数结合成一个堆栈,以便可以使用[反向波兰表示法](https://en.wikipedia.org/wiki/Reverse_Polish_notation)。 –

+0

我希望用户输入简单的总和,如“4 + 2”,应用程序将字符串解析为输入字符串数组,然后将输入字符串数组解析为两个数组,一个用于数字,一个用于符号如 numArray = [| 4; 2; |] symArray = [| “+” |]。 然后调用以这两个数组为参数的sum函数。 该函数将查看符号数组中的第一个符号,并根据该符号确定在num数组中的前两个元素上使用哪个运算符。并用新的计算出的数字返回一个新的数组数组。 –

回答

1

为响应答案@Liam唐纳利张贴到了自己的问题的方式:我会留下像“是搁置的问题真的是解决问题的最好方式“,只是评论如何更好地编写你现有的代码。

阵列切片和连接你在这里做的方式可以写成

let newNumArray = Array.append [| result |] numArray.[2..] 

不过,我会用F#列表,而不是数组为你的任务。通过列表,您可以进行模式匹配以访问前两个元素。在我看来,模式匹配胜过直接索引,因为您可以直接对角落案例进行编码,并让F#编译器提醒您角落案例。为操作员做同样的事情。您可以同时执行操作符和操作数。然后,它会是这个样子:

let rec sum2 (numArray : int list) (symArray : string list) = 
    let newNum, newSym = 
     match numArray with 
     | [] -> failwith "No numbers left to process" 
     | arg1 :: [] -> failwith "There's only one number left to process" 
     | arg1 :: arg2 :: args -> 
      match symArray with 
      | op1 :: ops -> 
       let result = 
        match op1 with 
        | "+" -> Add arg1 arg2 
        | "-" -> Sub arg1 arg2 
        | "*" -> Mul arg1 arg2 
        | _ -> failwithf "Operator not recognized: '%s'" op1 
       // Return the result, concatenate the non-processed 
       // numbers. Return the non-processed operators 
       result :: args, ops 
      | _ -> failwith "I've run out of operators?" 
<snip> 

此外,返回一个“默认结果”如果你不承认的运营商,是我认为非常危险的(即使做法是相当普遍)的东西

如果您使用列表(F#名单,这是),你可以直接通过head访问在索引1 ..元素:let newSymArray = symArray.Head或使用List.head

退一步每次看到自己写F#中for循环时间。他们编写起来很麻烦并且容易出错。大多数用于循环的典型用例都由F#库函数覆盖,因此请仔细阅读这些函数。您的打印循环可以通过下面的方式缩短书写时间:

newNumArray 
|> Seq.iter (printfn "%i") 
0

我已经成功地使执行我需要为它做任务的功能,我敢肯定有通过使用Array.copy以阵列的第一要素更加代码有效的方法与过滤器,但我是新来的F#,所以我只是把它我有信心

let rec sum (numArray : int[]) (symArray : string[]) = 
    let result = match symArray.[0] with 
       | "+" -> Add numArray.[0] numArray.[1] 
       | "-" -> Sub numArray.[0] numArray.[1] 
       | "*" -> Mul numArray.[0] numArray.[1] 
       | _ -> 0 

    let newNumArray = [| 
         for i = 0 to numArray.Length - 1 do 
          if i = 0 then yield result 
          if i > 1 then yield numArray.[i]|] 

    let newSymArray = [| 
         for i = 0 to symArray.Length - 1 do 
          if i > 0 then yield symArray.[i]|] 

    if newNumArray.Length > 1 then 
     sum newNumArray newSymArray 
    else 
     for i = 0 to newNumArray.Length - 1 do 
      printfn "%i" (newNumArray.[i]) 
+0

您的解决方案仍未充分利用F#,我在下面添加了一个备选答案和评论。 –

相关问题