F# error: expression was expected to have type unit

F# error: expression was expected to have type unit

我正在尝试用 F# 构建一个计算器。因此,我从用户那里获取有关要执行的操作的输入。对于输入 6,它应该显示科学操作的菜单,但是,它说表达式应该具有单位类型但具有浮点型。同样在 scientificFun() 函数中,最后一行是 'The expression was expected to have float but here has unit'。我不确定这是什么意思。坚持了几个小时。任何帮助,将不胜感激。谢谢!。 ** 或粗线表示发生错误的位置。

open System

let mutable ok = true
while ok do
Console.WriteLine("Choose a operation:\n1.Addition\n2.Substraction\n3.Multiplication\n4.Division\n5.Modulo\n6.Scientific")
let input= Console.ReadLine()  

let add() = 
    Console.WriteLine("Ok, how many numbers?")
    let mutable count = int32(Console.ReadLine())
    let numberArray = Array.create count 0.0
    for i in 0 .. numberArray.Length - 1 do
        let no = float(Console.ReadLine())
        Array.set numberArray i no    
    Array.sum numberArray

let expo() =
    Console.WriteLine("Enter the base")
    let getBase = Console.ReadLine()
    Console.WriteLine("Enter the exponent")
    let getExponent = Console.ReadLine()
    float(getBase) ** float(getExponent)

let sqRoot() = 
    Console.WriteLine("Enter a number")
    let no = float(Console.ReadLine())        
    Math.Sqrt no

let rec fact (n:float) =
    if n < 1.0 then 1.0
    else n * fact (n - 1.0)

let factorial() = 
    Console.WriteLine("Enter a number")
    let no = float(Console.ReadLine())
    fact(no)


let Trigsin() = 
    Console.WriteLine("Enter an angle")
    let angle = float(Console.ReadLine())
    Math.Sin angle
let Trigcos() =
    Console.WriteLine("Enter an angle")
    let angle = float(Console.ReadLine())
    Math.Cos angle
let Trigtan() =
    Console.WriteLine("Enter an angle")
    let angle = float(Console.ReadLine())
    Math.Tan angle

let logicalAnd() =
    Console.WriteLine("Enter first number")
    let first = int32(Console.ReadLine())
    Console.WriteLine("Enter second number")
    let second = int32(Console.ReadLine())
    float(first &&& second) 
let logicalOr() =
    Console.WriteLine("Enter first number")
    let first = int(Console.ReadLine())
    Console.WriteLine("Enter second number")
    let second = int(Console.ReadLine())
    float(first ||| second)
let logicalNot()=
    Console.WriteLine("Enter a number")
    let first = int32(Console.ReadLine())
    float(~~~first)
let sub x y = x - y 
let mul x y = x * y
let div x y = x / y
let MOD x y = x % y

let scientificFun() = 
    printfn("1.Exponential\n2.Square Root\n3.Factorial\n4.sin()\n5.cos()\n6.tan()\n7.AND\n8.OR\n9.NOT")
    let scientificInput = Console.ReadLine()
    match scientificInput with
    |"1" -> expo()
    |"2" -> sqRoot()
    |"3" -> factorial()
    |"4" -> Trigsin()
    |"5" -> Trigcos()
    |"6" -> Trigtan()
    |"7" -> logicalAnd()
    |"8" -> logicalOr()
    |"9" -> logicalNot()
    | _ -> **printfn("Choose between 1 - 9")**



match input with
| "1" -> printfn("The Result is: %f") (add())
//| "2" -> printfn("The Result is: %f") (sub A B)
//| "3" -> printfn("The Result is: %f") (mul A B)
///| "4" -> printfn("The Result is: %f") (div A B)
//| "5" -> printfn("The Result is: %f") (MOD A B)
| "6" -> **scientificFun()**
| _-> printfn("Choose between 1 and 6")
Console.WriteLine("Would you like to use the calculator again? y/n")
let ans = Console.ReadLine()
if ans = "n" then
    ok <- false
else Console.Clear()

The expression was expected to have float but here has unit

这是一条来自编译器的非常重要的消息,您应该尝试理解它为什么这么说,以及它的含义。用非常简单的术语来说,函数将值从一个域映射到另一个域。

如果你有函数,例如:

let makeStr (x:int) =
    string x

它的签名会告诉你它的输入和输出类型是什么:val makeStr : x:int -> string。在这种情况下,它需要一个 int 并将 returns 作为字符串。所以,这行得通:makeStr 10 但行不通 makeStr 10.,它会失败并显示以下消息:

error FS0001: This expression was expected to have type int but here has type float

在您的具体情况下,您可以检查 scientificFun() 的签名。 VSCode 和 VS2015 都会显示它是 val scientificFun : (unit -> float)。这是一个不接受输入(单位)和 returns 浮点数的函数。但是在选项 _ 中,您有 _ -> printfn("Choose between 1 - 9")printfn 打印到控制台,而不是 return 一个值,或者更确切地说它是 returns () (unit),这表明它有一个副作用,好吧, 打印到控制台。你不能 return 一个分支的浮点数和另一个分支的其他东西。有几种方法可以解决这个问题,其中一种方法是由@Funk 建议的,基本上将 return 值包装在 Option 类型中,这可能是最好的选择;^)。但是在这种情况下,让我们稍微作弊,并以一种快速而肮脏的方式修复您的功能:

将匹配表达式的最后一行更改为: | _ -> printfn("Choose between 1 - 9");0. 这里的通配符变成了一个复合表达式,打印出来,但最后 returns 0.,这是一个浮点数,F# 编译器很高兴。

那么你还需要在最后一场比赛中修正选项6。如果你看上面,你可以看到所有其他分支都打印到控制台,return 单元也应该如此,但是 scientificFun 的签名会告诉你它 returns float,那么它是哪个?只需将分支更改为看起来像所有其他表达式: | "6" -> printfn("The Result is: %f") <| scientificFun()

一旦你完成了这项工作,我建议你可能 post 把它放到 CodeReview 上,在那里它可以用更惯用的 F#/函数式风格重新设计。

此外,这些参考资料应该对您有所帮助:

Match Expressions
Pattern Matching
Match Expressions 2
F# Expressions and Syntax
Thinking Functionally

加1

您还可以使 ScientificFun() 成为调用自身的递归函数。

let rec scientificFun() = 
    printfn("1.Exponential\n2.Square Root\n3.Factorial\n4.sin()\n5.cos()\n6.tan()\n7.AND\n8.OR\n9.NOT")
    let scientificInput = Console.ReadLine()
    match scientificInput with
    |"1" -> expo()
    |"2" -> sqRoot()
    |"3" -> factorial()
    |"4" -> Trigsin()
    |"5" -> Trigcos()
    |"6" -> Trigtan()
    |"7" -> logicalAnd()
    |"8" -> logicalOr()
    |"9" -> logicalNot()
    | _ -> scientificFun()