输入检查有效的double或int

时间:2015-10-21 20:35:44

标签: .net validation f# user-input

我正在尝试创建一个接受字符串的方法,并尝试根据第二个参数将其解析为int或double。我的代码看起来正确,但给我一个类型不匹配。但看起来它们是正确的类型......

我希望获得有关如何修复它的建议。以下是我到目前为止的地方。

let double = Type.GetType("System.Double")
let int32 = Type.GetType("System.Int32")

let rec checkinput input (msType:Type)= 
    //force them to give you a good number
    let ConsoleTrap parsed msType=
        if fst parsed then
            snd parsed //return the parsed value
        else //the parse failed
            Console.WriteLine "Enter a real number"
            let newInput = Console.ReadLine()
            checkinput newInput
    //do it slightly differently based on whether we want an int or double
    if msType = double then
        ConsoleTrap (Double.TryParse input) (double)

    else 
        ConsoleTrap (Int32.TryParse input) (int32)

3 个答案:

答案 0 :(得分:1)

问题的第一部分是ConsoleTrap内的递归调用缺少参数。您只需提供newInput,但也需要msType。您可以将该行更改为:

checkinput newInput msType

现在,这仍然没有用,但我们更接近了。现在的问题是,不清楚函数的结果应该是什么。在:

if msType = double then
    ConsoleTrap (Double.TryParse input) (double)
else 
    ConsoleTrap (Int32.TryParse input) (int32)

... true分支返回floatfalse分支返回int。所以这是一个类型检查错误。您可以通过使函数checkinput成为通用函数并仅处理intdouble个案例(但使其返回'T)来解决此问题。然后,您可以添加不安全的unbox。以下内容适用:

let rec checkinput input : 'TResult = 
    //force them to give you a good number
    let inline doer parsed : 'TLocal =
        if fst parsed then
            snd parsed //return the parsed value
        else //the parse failed
            Console.WriteLine "Enter a real number"
            let newInput = Console.ReadLine()
            unbox<'TLocal> (checkinput newInput)
    //do it slightly differently based on whether we want an int or double
    if typeof<'TResult> = double then
        unbox<'TResult> (doer (Double.TryParse input))
    else 
        unbox<'TResult> (doer (Int32.TryParse input))

那说,现在它变得有点难看,所以我可能不想使用这种代码。如果没有这个,你可能会有更多的重复,但如果有一些重复,你可以用一种更易读的方式解决原始问题。

答案 1 :(得分:1)

我决定试一试,结束了两种不同的事情 第一个依赖于“duck typing”。

let inline checkInput input =
  let parsed = ref Unchecked.defaultof<_>

  let rec aux input =
    if (^a : (static member TryParse : string * ^a byref -> bool) (input, &parsed.contents)) then
      !parsed
    else
      Console.WriteLine "Enter a real number"
      aux (Console.ReadLine ())

  aux input

// usage
let n = checkInput<int> (Console.ReadLine ())
// let n : int = checkInput (Console.ReadLine ()) // equivalent syntax
let d = checkInput<double> (Console.ReadLine ())
// works for any type with a matching TryParse member
let dt = checkInput<DateTime> (Console.ReadLine ())

第二个依赖于discriminated union

type ParseType = IntType | DoubleType
type ParseResult = IntResult of int | DoubleResult of double

// (note "input" arg could be η-converted)
let checkInput pType input =
  let rec aux parser resultCtor input =
    match parser input with
      true, parsed -> resultCtor parsed
    | _ ->
      Console.WriteLine "Enter a real number"
      aux parser resultCtor (Console.ReadLine ())

  // use the function associated with given "type case"
  match pType with
    IntType    -> aux Int32.TryParse IntResult input
  | DoubleType -> aux Double.TryParse DoubleResult input

// usage
let n = checkInput IntType (Console.ReadLine ())
let d = checkInput DoubleType (Console.ReadLine ())

答案 2 :(得分:0)

在查看Tomas回答后,我能够以不同的方式编译它,使用box然后取消框。

let double = Type.GetType("System.Double")
let int32 = Type.GetType("System.Int32")

//takes the user input and forces them to enter a valid number
// can return either valid doubles or ints
let rec checkinput (input) (msType:Type)  = 
    //force them to give you a good number
    let ConsoleTrap (parsed: obj) (msType :Type)=
        let parsed = unbox parsed
        if fst parsed then
            snd parsed //return the parsed value
        else
            Console.WriteLine "Enter a real number"
            let newInput = Console.ReadLine()
            checkinput newInput msType
    //do it slightly differently based on whether we want an int or double
    if msType = double then
        let parsed = Double.TryParse input
        ConsoleTrap (box parsed) double

    else 
        let parsed = Int32.TryParse input
        ConsoleTrap (box parsed) int32