繁体   English   中英

F#如何编写一个带有int列表或字符串列表的函数

[英]F# How to write a function that takes int list or string list

我在F#中乱搞并尝试编写一个可以采用int liststring 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的签名具有通用元素。 还有更多的是内联函数在这里

您正在对此处概述的类型推断系统的自动泛化遇到值限制

特别,

案例4:添加类型参数。

解决方案是使您的函数通用,而不是仅仅使其参数通用。

let inline contains5< ^T when ^T : (static member op_Explicit: ^T -> int) > (xs : ^T list)  =
    List.map int xs
    |> List.contains 5

您必须使函数内联,因为您必须使用静态解析的类型参数,并且必须使用静态解析的类型参数才能使用成员约束来指定类型必须可转换为int。 作为概述这里

这已经在上面正确回答了,所以我只是想知道为什么我认为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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM