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

时间:2018-01-08 20:21:36

标签: types f# 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)

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

2 个答案:

答案 0 :(得分:7)

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

好的,现在是实际答案

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

从上下文中,我理解你实际想要做的是用它的扩展版本替换有问题的数组。为此,您需要声明数组mutable,然后使用&#34;破坏性更新&#34; operator <-

black <- Array.append black paintArr.[i,j]

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

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

> let x = ()
val x : unit = ()

所以要从所有分支机构实现&#34;相同的类型&#34;规则,您可以让第三个分支只返回unit值,而不调用任何函数:

    | None -> ()

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

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)

但请注意,这仍然无法编译,因为其中还有其他错误。首先,Option.get仅在paintArr.[i,j].colorSome值时有效,但在其None时会崩溃。其次,即使此功能成功,它也会返回一种颜色,但是您会尝试将其与None进行比较,而paintArr.[i,j].color不是颜色。这将产生编译时错误。

此时有点难以推断出你真正想做的事情,但我会尝试猜测。我将猜测 Color option类型为Color,其中White是包含BlackOption.get( ... )和某些内容的枚举其他颜色。
如果确实如此,则不需要匹配paintArr.[i,j].color,而是匹配Black本身,并处理三种情况:(1)当Some包含在White中时},(2)当颜色为Some包裹在None时,以及(3)当颜色为 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 -> () 时:

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 -> () 在哪里?我想你只是忘了为它添加一个循环:

<Project Sdk="Microsoft.NET.Sdk">
 <PropertyGroup>
  <TargetFramework>netstandard2.0</TargetFramework>
  <AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
 <PackageReference Include="Microsoft.NET.Sdk.Functions" 
     Version="1.0.6" />
</ItemGroup>
<ItemGroup>
 <None Update="host.json">
 <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  <CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>

答案 1 :(得分:2)

对于不同的返回类型,我建议使用discriminated unions。您还可以阅读更多here。 但是根据您提供的代码,它似乎与问题本身不匹配。我建议首先重构你的初始函数,使其更清晰。