【问题标题】:F# error: expression was expected to have type unitF# 错误:表达式应具有类型单位
【发布时间】:2017-03-26 01:20:00
【问题描述】:

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

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

【问题讨论】:

  • 模式匹配的所有返回值必须是同一类型。匹配scientificInput 的所有函数都返回float,但printfn 除外,它返回unit
  • 谢谢@Funk..你能给我一个想法,我怎样才能做到这一点。?。按6后,我想显示科学菜单
  • 有几种方法。您可以在匹配之前检查int 是否在正确的范围内,因此在模式匹配中将不再需要printfn。您还可以使用option type“捕获”恶意输入。所有好的输入都会导致Some('float'),而错误的输入会导致None

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


【解决方案1】:

表达式应该是浮点数,但这里有单位

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

如果你有一个函数,例如:

let makeStr (x:int) =
    string x

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

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

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

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

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

【讨论】:

  • 加1 |> +1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-28
  • 1970-01-01
  • 2021-08-30
  • 1970-01-01
  • 2019-06-12
  • 1970-01-01
相关资源
最近更新 更多