F#在模式匹配中返回不同的类型

2 f# types pattern-matching

我试图弄清楚如何处理模式匹配的情况,它根据匹配返回不同的类型,我知道它必须为每个分支返回相同的类型,所以我不知道处理这种情况的"正确"方式是什么是:

我尝试在下面做一个我的困惑的例子,paintArr是一个数组,代表一个可以包含一些颜色或一个空槽的托盘.

paintArr.[i,j] .color属于Color选项,包含黑色和白色.

每个插槽的模式匹配应决定颜色是黑色还是白色,并将其索引添加到适当的阵列.

let sort (paintArr: Pallete) =
    let black = [||]
    let white = [||]
    for i = 0 to 5 do
        for j = 0 to 5 do
            match ((Option.get (paintArr.[i,j])).color) with
                | White -> Array.append white paintArr.[i,j]
                | Black -> Array.append black paintArr.[i,j]
                | None -> "not sure what to do here"
    (black, white)
Run Code Online (Sandbox Code Playgroud)

基本上,我认为我的问题归结为:你如何处理这样的情况,在某些情况下我会得到一个匹配,要求我什么也不做,或者可能只是与其他情况不同的东西?

Fyo*_*kin 7

序言:很明显,你对F#缺乏经验.如果这是真的,我建议你先读一些书或一套教程(我总是推荐https://fsharpforfunandprofit.com/).您正在尝试使用比完整初学者应该处理的代码更复杂的代码.


好的,现在回答实际问题

首先,请注意,Array.append不会"更改"("更新","修改")数组,而是返回一个新数组 - 您给它的原始数组和新元素的串联.有了这些知识,很容易看出你的Array.append电话是无用的:它们会返回一些东西,但你只是立即扔掉它.

从上下文中,我了解到你真正想要做的是用它的扩展版本替换有问题的数组.为此,您需要声明您的数组mutable,然后使用"破坏性更新"运算符<-:

black <- Array.append black paintArr.[i,j]
Run Code Online (Sandbox Code Playgroud)

<-F#中的破坏性更新运算符=与C语言中的赋值语句等效.

现在,如果您使用这样的破坏性更新运算符,则此类表达式的结果类型将为unit- 空类型,用于表示"无值".这种类型只有一个值,它被写成两个括号,它们之间没有任何内容.例如:

> let x = ()
val x : unit = ()
Run Code Online (Sandbox Code Playgroud)

因此,为了实现"来自所有分支的相同类型"规则,您可以让第三个分支只返回一个unit值,而不调用任何函数:

    | None -> ()
Run Code Online (Sandbox Code Playgroud)

将以上所有内容应用到您的代码中,我们得到:

let sort (paintArr: Pallete) =
    let mutable black = [||]
    let mutable white = [||]
    for i = 0 to 5 do
            match ((Option.get (paintArr.[i,j])).color) with
                | White -> white <- Array.append white paintArr.[i,j]
                | Black -> black <- Array.append black paintArr.[i,j]
                | None -> ()
    (black, white)
Run Code Online (Sandbox Code Playgroud)

但请注意,这仍然无法编译,因为其中还有其他错误.首先,Option.get只有当值paintArr.[i,j].color是一个Some值时才会起作用,但是当它出现时会崩溃None.其次,即使这个功能成功,它也会返回一种颜色,但是你会尝试将它与None颜色进行比较.这将产生编译时错误.

在这一点上推断你真正想做的事情有点难,但我会试着猜测.我将猜测paintArr.[i,j].color是类型的Color option,其中,Color是包括枚举White,Black和一些其他的颜色.
如果这是真的,你需要匹配不上Option.get( ... ),但paintArr.[i,j].color本身,并处理三种情况:(1)当颜色被Black包裹Some,(2)当颜色被White包裹Some,和(3)当颜色是None:

     for i = 0 to 5 do
        match paintArr.[i,j].color with
            | Some White -> white <- Array.append white paintArr.[i,j]
            | Some Black -> black <- Array.append black paintArr.[i,j]
            | None -> ()
Run Code Online (Sandbox Code Playgroud)

最后,我可以看到一个循环i,但是在哪里j?我想你只是忘了为它添加一个循环:

  for i = 0 to 5 do
     for j = 0 to 5 do
        match paintArr.[i,j].color with
            | Some White -> white <- Array.append white paintArr.[i,j]
            | Some Black -> black <- Array.append black paintArr.[i,j]
            | None -> ()
Run Code Online (Sandbox Code Playgroud)