2016-04-24 140 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#,我在下面添加了一個備選答案和評論。 –

相關問題