F#:跨度、提升和底部类型(或缺少)

F#: Span, raise, and the bottom type (or lack thereof)

在我发表这条评论后https://github.com/fsharp/fslang-suggestions/issues/349#issuecomment-1124206512 我仍然觉得我错过了...

为了 reader 的方便,此处复制了示例代码:

let spanOfOptString(os: Option<string>) =
  match os with Some(s) -> s.AsSpan()
                | None -> raise(Exception())

error FS0412: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.

因此,F# 将无 return 函数 raise 键入为 Exception -> 'a 并使用自由 'a(“OCaml 方式”),并且类型变量发生了绑定到 byref 类型 ReadOnlySpan,这是非法的。我觉得我因为我没有犯下的罪行而受到惩罚......

我可以找到类似

的解决方法
let checkedSpanOfString(os: Option<string>) =
  match os with Some(s) -> s.AsSpan()
                | None -> raise(Exception())  // 'a = unit
                          ReadOnlySpan.Empty  // both arms: ReadOnlySpan<char>

https://sharplab.io/#gist:32b520574fde97de8d7389ab04f64bc4

但是恕我直言,这有点难看。而且我不认为我们应该期待 .Empty 等同于 all byref 类型的东西? (我不认为我曾经使用过除 (ReadOnly)Span/Memory 之外的任何其他 byref 类型,但这是另一回事)

虽然 F# 核心团队似乎并没有打算将底层类型引入语言(这可能是一个明智的工程决策),
有人有更好的替代方法来完成这项工作吗?

更新

@chadnt 的回答可以内联得到

let checkedSpanOfString(os: Option<string>) =
  let s = match os with Some(s) -> s
                        | None -> raise(Exception())
  s.AsSpan()

https://sharplab.io/#gist:a5eab805c539c45048b4072fa7b096c5

它的IL看起来比我原来的版本简单多了

看来先给字符串赋值似乎就解决了。

open System

let valueOrRaise = function
    | Some v -> v
    | None -> raise(Exception())

let checkedSpanOfString (os: string option) =
    let s = valueOrRaise os
    s.AsSpan()

https://sharplab.io/#gist:2ca959f498be87f1b52212182af237b4

在 FSI 中:

> (checkedSpanOfString (Some "foo")).ToString();;
val it: string = "foo"