递归函数中的空引用异常

Lea*_*erX 1 f#

下面的代码来自https://www.manning.com/books/real-world-function-programming的第8章

当我运行代码时,我在 testClientTree 中收到空引用异常。我检查了这本书的勘误表,但没有找到任何与此相关的内容。

type Client =
  { Name : string
    Income : int
    YearsInJob : int
    UsesCreditCard : bool
    CriminalRecord : bool }

let john = 
  { Name = "John Doe"  
    Income = 40000
    YearsInJob = 1
    UsesCreditCard = true
    CriminalRecord = false }

type ClientTests = 
  { Check   : Client -> bool
    Report : Client -> unit }

type QueryInfo =
  { Title : string
    Test : Client -> bool
    Positive : Decision
    Negative : Decision }
    
and Decision = 
  | Result of string  
  | Query of QueryInfo

let rec tree = 
    Query({ Title = "More than $40k" 
            Test = (fun cl -> cl.Income > 40000)
            Positive = moreThan40; Negative = lessThan40 })
and moreThan40 = 
    Query({ Title = "Has criminal record"
            Test = (fun cl -> cl.CriminalRecord)
            Positive = Result("NO"); Negative = Result("YES") })
and lessThan40 = 
    Query({ Title = "Years in job"
            Test = (fun cl -> cl.YearsInJob > 1)
            Positive = Result("YES"); Negative = usesCredit })
and usesCredit = 
    Query({ Title = "Uses credit card"
            Test = (fun cl -> cl.UsesCreditCard)
            Positive = Result("YES"); Negative = Result("NO") })

let rec testClientTree(client, tree) =
  match tree with
  | Result(msg) ->
      printfn "  OFFER A LOAN: %s" msg
  | Query(qi) ->
      let s, case = if (qi.Test(client)) then "yes", qi.Positive
                    else "no", qi.Negative
      printfn "  - %s? %s" qi.Title s
      testClientTree(client, case)

[<EntryPoint>]
let main argv =
    testClientTree(john, tree)
    0
Run Code Online (Sandbox Code Playgroud)

Phi*_*ter 5

我不知道为什么书上有这个初始化代码,但是失败的原因是因为数据实际上没有初始化。

你需要这样做:

let rec tree = 
    Query({ Title = "More than $40k" 
            Test = (fun cl -> cl.Income > 40000)
            Positive = 
                Query({ Title = "Has criminal record"
                        Test = (fun cl -> cl.CriminalRecord)
                        Positive = Result("NO")
                        Negative = Result("YES") })
            Negative = 
                Query({ Title = "Years in job"
                        Test = (fun cl -> cl.YearsInJob > 1)
                        Positive = Result("YES");
                        Negative = 
                            Query({ Title = "Uses credit card"
                                    Test = (fun cl -> cl.UsesCreditCard)
                                    Positive = Result("YES"); Negative = Result("NO") })})})
Run Code Online (Sandbox Code Playgroud)

正是由于这样的原因,如果可以的话,最好不要定义一堆相互递归的东西。