F#错误:表达式应该具有类型单位

时间:2016-11-11 18:44:46

标签: f# functional-programming f#-interactive f#-3.0

我试图在F#中构建一个计算器。因此,我从用户那里获取有关要执行的操作的输入。对于输入6,它应该显示科学操作的菜单,但是,它表示表达式应该具有类型单位但具有类型float。而且在scientificFun()函数中,对于最后一行,它说,'表达式预计会浮动,但这里有单位'。我不确定这意味着什么。被困在这几个小时。任何帮助,将不胜感激。谢谢!。 **或粗线显示出现错误的位置。

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()

1 个答案:

答案 0 :(得分:3)

  

表达式预计有浮动但这里有单位

这是编译器发出的一条非常重要的信息,您应该尝试理解它为什么这么说,以及它意味着什么。简单来说,函数将值从一个域映射到另一个域。

如果你有一个功能,例如:

let makeStr (x:int) =
    string x

它的签名会告诉你它的输入和输出类型是什么:val makeStr : x:int -> string。在这种情况下,它接受一个int并将其作为字符串返回。因此,这有效:makeStr 10但不会makeStr 10.,它将失败并显示以下消息:

  

错误FS0001:此表达式应具有类型       int但这里有类型       浮

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

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

然后你还需要在最后的比赛中修复选项6。如果你看上面你可以看到所有其他分支打印到控制台,所以应该返回单位,但scientificFun的签名将告诉你它返回浮点数,那么它是哪一个?只需将分支更改为所有其他表达式: | "6" -> printfn("The Result is: %f") <| scientificFun()

一旦你完成了这项工作,我建议你可以将它发布到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()