[英]F# How to write a function that takes int list or string list
我在F#中乱搞并尝试编写一个可以采用int list
或string list
的函数。 我编写了一个逻辑上通用的函数,因为我只能修改参数的类型,它将与两种类型的列表一起运行。 但我不能一般地定义两者。
这是我的函数,没有类型注释:
let contains5 xs =
List.map int xs
|> List.contains 5
当我尝试注释函数以获取通用列表时,我收到警告FS0064: the construct causes the code to be less generic than indicated by the type annotations
。 从理论上讲,我不需要注释这是通用的,但无论如何我都试过了。
我可以在两个单独的文件中编译它,一个用
let stringtest = contains5 ["1";"2";"3";"4"]
和另一个
let inttest = contains5 [1;2;3;4;5]
在每个文件中,编译成功。 或者,我可以将函数定义和其中一个测试发送给解释器,类型推断也可以正常进行。 如果我尝试编译,或发送到解释器,函数定义和两个测试,我收到error FS0001: This expression was expected to have type string, but here has type int
。
我是否误解了打字应该如何运作? 我有一个函数,其代码可以处理一个int列表或一个字符串列表。 我可以用其中任何一个成功测试它。 但我不能在一个处理两者的程序中使用它?
您可以使用inline
来防止将函数固定到特定类型。
在FSI中,交互式REPL:
> open System;;
> let inline contains5 xs = List.map int xs |> List.contains 5;;
val inline contains5 :
xs: ^a list -> bool when ^a : (static member op_Explicit : ^a -> int)
> [1;2;3] |> contains5;;
val it : bool = false
> ["1";"2";"5"] |> contains5;;
val it : bool = true
请注意,contains5的签名具有通用元素。 还有更多的是内联函数在这里 。
这已经在上面正确回答了,所以我只是想知道为什么我认为F#似乎使这很难/迫使我们失去类型安全是一件好事。 我个人认为这些在逻辑上是等价的:
let inline contains5 xs = List.map int xs |> List.contains 5
let stringTest = ["5.00"; "five"; "5"; "-5"; "5,"]
let intTest = [1;2;3;4;5]
contains5 stringTest // OUTPUT: System.FormatException: Input string was not in a correct format.
contains5 intTest // OUTPUT: true
内联时,编译器将创建该函数的两个逻辑上不同的版本。 当在list<int>
上执行时,我们得到一个布尔结果。 当在list<string>
上执行时,我们得到一个布尔结果或一个异常。 我喜欢F#推动我承认这一点。
let maybeInt i =
match Int32.TryParse i with
| true,successfullyParsedInteger -> Some successfullyParsedInteger
| _ -> None
let contains5 xs =
match box xs with
| :? list<int> as ixs ->
ixs |> List.contains 5 |> Ok
| :? list<string> as sxs ->
let successList = sxs |> List.map maybeInt |> List.choose id
Ok (successList |> List.contains 5)
| _ ->
Error "Error - this function expects a list<int> or a list<string> but was passed something else."
let stringTest = ["5.00"; "five"; "5"; "-5"; "5,"]
let intTest = [1;2;3;4;5]
let result1 = contains5 stringTest // OUTPUT: Ok true
let result2 = contains5 intTest // OUTPUT: Ok true
强迫我询问if some of the values in the string list cannot be parsed, should I drop out and fail, or should I just try and look for any match on any successful parse results?
。
我上面的方法太可怕了。 我将操作字符串的函数与对整数进行操作的函数分开。 我认为你的问题是学术问题,而不是一个真实的用例,所以我希望我在这里没有过多的切线!
免责声明:我是初学者,不相信我说的任何话。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.