如何处理异常输入并停止运行F#中的其余功能?

Ton*_*son 1 f#

我一直在学习F#,我正在编写一个工具.除非我需要处理无效输入或异常情况,否则一切正常.

在F#中处理此问题的推荐方法是什么?我的函数的构造和使用方式我不知道如何发回一条消息,告诉调用函数由于输入错误而导致调用失败以及类似于C#的循环继续需要发生.

我因为失去了回归而受苦.我可以从F#函数返回其中的任何位置,还是必须在最后一行?

这是我的一些代码示例,其中输入在某些情况下基本上是空的,我正在检测它.我需要阻止运行过程中的步骤.

let SchemaQueryString s =
    let sqsValid s = 
        let Strcat (x : string) (y : string) = x + ", " + y;
        let RecFieldName (x : MeasurementRecord) = x.FieldName;    
        let mapr = List.map RecFieldName s.MeasurementTypes;
        let cores = List.reduce Strcat mapr;
        "SELECT ProductionCode, TestTime, " + cores + " FROM " + s.TemplateName + " ORDER BY ProductionCode, TestTime";

    match s.MeasurementTypes.Length with
    | 0 -> ""
    | _ -> sqsValid s;

let TemplateMigration tcs rr =
    let sql = SchemaQueryString tcs;
    let sqlc = new SqlCommand(sql, QCOld);
    let sqldr = sqlc.ExecuteReader();
    ignore (sqldr.Read());
    ...
Run Code Online (Sandbox Code Playgroud)

我需要中止TemplateMigration函数并立即返回sql变量与""的匹配.或构造某种类型的联合类型,表明不能构造sql查询字符串,因为对于特定情况,它无法完成.

谢谢你的帮助.我正逐渐搞清楚这种语言,我非常喜欢它,但我正在努力解决它的某些方面,我不知道如何取代关于如何用功能性思想做一些事情的程序性想法.

Dan*_*her 8

当第一次使用函数式语言时,很多人认为一切都是表达式.这意味着使用控制流表达式执行控制流.

那么语句和表达式之间的区别是什么?

语句没有价值,即它不是类型的实例.表达式具有一个值(即使该值是特殊类型unit,它具有一个()不表示任何值的实例.)

在过程语言中,我们使用语句来控制执行流程,因此:

class Program
{
    static void Main(string[] args)
    {
        string str;

        if (DateTime.Now.DayOfWeek == DayOfWeek.Monday)
            return;
        else if (args.Length >= 2)
            str = args[1];
        else
            str = "Hello";

        Console.WriteLine(str);
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我们定义一个变量str类型string有一个值null.然后我们要么忽略它,return如果它是星期一,请分配,args[1]如果可用或"Hello"以其他方式打印它.

当控制流语句长达几行时,这种编程是相当安全的.但是,一旦语句变得大于页面长度,或者复杂和嵌套,我们就更有可能引入错误,通常是十亿美元的错误.

纯函数式语言使用控制流表达式.这意味着if表达式具有值!让我们在前面的代码示例中慢慢实现控件.首先让我们解决分配字符串的问题str.

let str =
    if args.Length >= 2 then
        args.[1]
    else 
        "Hello"
Run Code Online (Sandbox Code Playgroud)

在这里,我们看到我们直接绑定if表达式的值str.所述的两个分支(子表达式)if表达必须评估为类型的实例string.我们简直不能忘记为字符串赋值,因为编译器会在我们尝试时抛出错误.

但是,在我们希望在控制流程的不同分支中执行不同类型的事情时,似乎存在许多情况.在我们的例子中,如果它是星期一,我们不想做任何事情.这就是受歧视的工会的力量发挥作用的地方.这些允许我们将异构类型组合成一个整体,保留基于表达式的语言的强大功能,以便在每个级别对我们的代码进行类型检查.

在我们的例子中,我们不需要创建新的联合类型,因为该option类型已经包含此功能.因此,我们重写:

open System

[<EntryPoint>]
let Main args =

    let str =
        if DateTime.Now.DayOfWeek = DayOfWeek.Monday then
            None
        elif args.Length >= 2 then
            Some(args.[1])
        else 
            Some("Hello")

    match str with
    | Some(str) -> Console.WriteLine(str)
    | None      -> ()

    Environment.ExitCode 
Run Code Online (Sandbox Code Playgroud)

现在我们从if表达式返回的值是string option(或Option<string>在C#中),然后我们使用模式匹配来安全地处理控制流的所有可能结果.

当您返回unit值时,TemplateMigration可以简单地从if表达式的两个分支返回相同的值,因此:

let TemplateMigration tcs rr =
    let sql = SchemaQueryString tcs
    if sql = null || sql.Length = 0 then
        ()
    else 
        let sqlc = new SqlCommand(sql, QCOld)
        let sqldr = sqlc.ExecuteReader()
        ignore (sqldr.Read())
Run Code Online (Sandbox Code Playgroud)

但是从它返回一个option值可能会更好SchemaQueryString

let SchemaQueryString s =
    ... // Elided

    match s.MeasurementTypes.Length with
    | 0 -> None
    | _ -> Some(sqsValid s)
Run Code Online (Sandbox Code Playgroud)

在整个代码中"传播"强类型值.