F# 结果单元测试在没有类型注释的情况下失败 - 在这种情况下我可以避免类型注释吗?
F# Result Unit Test Fails without type annotation - Can I avoid the type annotation in this case?
我正在做一些 F# 练习,任务是实现一个名为 clean
的函数,它接受一个字符串输入和 returns 一个已解析的数字。
let clean input =
input
|> Seq.filter Char.IsDigit
|> Seq.fold (fun acc cur ->
if acc = "" && cur = '1' then
acc
else acc + string cur) ""
|> uint64
|> Ok
这是我的临时解决方案。但是下面的单元测试失败了:
[<Fact>]
let ``Cleans the number`` () =
let expected: Result<uint64,string> = Ok 2234567890UL
let parsed = clean "(223) 456-7890"
parsed |> should equal expected
失败:
FsUnit.Xunit+MatchException : Exception of type
'FsUnit.Xunit+MatchException' was thrown. Expected: Equals Ok
2234567890UL Actual: was
Microsoft.FSharp.Core.FSharpResult2[System.UInt64,System.Object]<br>
at FsUnit.Xunit.Assert.That.Static[a](a actual, IMatcher
1 matcher)
at PhoneNumberTest.Cleans numbers with dots() in
所以我添加了一个类型注释:let clean input: Result<uint64,string> // function body is the same
我可以避免类型注释吗?第一个解决方案失败的技术原因是什么?
如果没有类型注释,您的 clean
函数将被推断为具有通用类型 seq<char> -> Result<uint64,'a>
,因此在您需要类型注释的情况下。
编译器推断泛型类型的原因是您总是 return Result<'ok,'error>
类型的 OK
分支。
正如您的函数名称所暗示的,也许 Result
不是最合适的 return 类型?
这里的问题是编译器无法仅从成功值 Ok 2234567890UL
推断出您的 Result
在失败情况下的类型。当它不知道时,它只使用 obj
,因此默认的推断类型是 Result<uint64, obj>
。比较不同类型的对象总是 false
.
这有点不幸,因为您正在比较两个值,因此它们必须具有相同的类型。提供 should
和 equal
操作的 FsUnit
库不是严格类型化的,允许您比较不同类型的值。你可以这样写:
1 |> should equal "1"
有一个 library FsUnitTyped
实现了 FsUnit 的类型化版本。我没有这方面的经验,但看起来你可以使用它并写:
[<Fact>]
let ``Cleans the number`` () =
let expected = Ok 2234567890UL
let parsed = clean "(223) 456-7890"
parsed |> shouldEqual expected
这将解决您的问题 - 编译器可以推断 expected
的类型必须与 parsed
的类型相同,因此它会自动使用正确的类型。
我正在做一些 F# 练习,任务是实现一个名为 clean
的函数,它接受一个字符串输入和 returns 一个已解析的数字。
let clean input =
input
|> Seq.filter Char.IsDigit
|> Seq.fold (fun acc cur ->
if acc = "" && cur = '1' then
acc
else acc + string cur) ""
|> uint64
|> Ok
这是我的临时解决方案。但是下面的单元测试失败了:
[<Fact>]
let ``Cleans the number`` () =
let expected: Result<uint64,string> = Ok 2234567890UL
let parsed = clean "(223) 456-7890"
parsed |> should equal expected
失败:
FsUnit.Xunit+MatchException : Exception of type 'FsUnit.Xunit+MatchException' was thrown. Expected: Equals Ok 2234567890UL Actual: was Microsoft.FSharp.Core.FSharpResult
2[System.UInt64,System.Object]<br> at FsUnit.Xunit.Assert.That.Static[a](a actual, IMatcher
1 matcher)
at PhoneNumberTest.Cleans numbers with dots() in
所以我添加了一个类型注释:let clean input: Result<uint64,string> // function body is the same
我可以避免类型注释吗?第一个解决方案失败的技术原因是什么?
如果没有类型注释,您的 clean
函数将被推断为具有通用类型 seq<char> -> Result<uint64,'a>
,因此在您需要类型注释的情况下。
编译器推断泛型类型的原因是您总是 return Result<'ok,'error>
类型的 OK
分支。
正如您的函数名称所暗示的,也许 Result
不是最合适的 return 类型?
这里的问题是编译器无法仅从成功值 Ok 2234567890UL
推断出您的 Result
在失败情况下的类型。当它不知道时,它只使用 obj
,因此默认的推断类型是 Result<uint64, obj>
。比较不同类型的对象总是 false
.
这有点不幸,因为您正在比较两个值,因此它们必须具有相同的类型。提供 should
和 equal
操作的 FsUnit
库不是严格类型化的,允许您比较不同类型的值。你可以这样写:
1 |> should equal "1"
有一个 library FsUnitTyped
实现了 FsUnit 的类型化版本。我没有这方面的经验,但看起来你可以使用它并写:
[<Fact>]
let ``Cleans the number`` () =
let expected = Ok 2234567890UL
let parsed = clean "(223) 456-7890"
parsed |> shouldEqual expected
这将解决您的问题 - 编译器可以推断 expected
的类型必须与 parsed
的类型相同,因此它会自动使用正确的类型。