我正在尝试使用Span实现二进制解析器组合器库。我不确定这是否是一个好主意,我只是想了解更多有关这两者的信息。
我之前已经使用解析器组合器编写了一个小型的二进制解析器,它的工作原理非常完美。
代码如下:
type ByteRange =
{ Bytes : byte array
BeginIndex : int
EndIndex : int }
type ParserError<'err> =
| EndOfStream
| FormatError of 'err
type Parser<'T, 'err> = Parser of (ByteRange -> Result<'T * ByteRange, ParserError<'err>>)
let succeed value = Parser <| fun bytes -> Ok(value, bytes)
let fail error = Parser <| fun _ -> Error error
let internal fromResult result =
Parser <| fun bytes ->
match result with
| Ok value -> Ok(value, bytes)
| Error error -> Error(FormatError error)
let internal map f (Parser parse) =
Parser <| fun byteRange ->
match parse byteRange with
| Ok(value', state') -> Ok(f value', state')
| Error error -> Error error
...
Run Code Online (Sandbox Code Playgroud)
我尝试使用Span而不是ByteRange来实现它,但我做不到。
这是我尝试过的:
module BinaryParser
open System
open System.Runtime.CompilerServices
type ParserError<'err> =
| EndOfStream
| FormatError of 'err
[<Struct; IsByRefLike>]
type Success<'a> = {
Value: 'a
Bytes: Span<byte>
}
[<Struct; IsByRefLike>]
type ParsingResult<'a, 'err> =
| Success of success:Success<'a>
| Failure of failure:ParserError<'err>
type Parser<'T, 'err> =
Span<byte> -> ParsingResult<'T, ParserError<'err>>
let succeed (value: 'a) =
fun (bytes: Span<byte>) ->
Success { Value = value; Bytes = bytes }
let fail error =
fun _ ->
Failure error
let internal fromResult result =
fun bytes ->
match result with
| Ok value -> Success { Value = value; Bytes = bytes }
| Error error -> Failure (FormatError error)
let internal map f (parse: Parser<_, _>) =
fun bytes ->
match parse bytes with
| Success { Value = value'; Bytes = bytes' } -> Success { Value = f value'; Bytes = bytes' }
| Failure error -> Failure error
Run Code Online (Sandbox Code Playgroud)
我map在该行的函数中收到以下错误match parser bytes with:错误FS0418:此时无法使用byref类型的值'bytes'
这是什么意思?为什么我不能在这里使用Span?有人尝试过使用Span实现解析器组合器吗?您将如何解决这个问题?
提前致谢。
不支持此模式(Span或其他byref类似的结构作为高阶函数参数):
let internal map f (parse: Parser<_, _>) =
fun bytes ->
match parse bytes with
| Success { Value = value'; Bytes = bytes' } -> Success { Value = f value'; Bytes = bytes' }
| Failure error -> Failure error
Run Code Online (Sandbox Code Playgroud)
一个简单的形式:
let foo (f: Span<int> -> int) (x: Span<int>) = f x
Run Code Online (Sandbox Code Playgroud)
f也会产生错误。有一些带有byref-like类型和类型缩写的细微怪癖将错误隐藏起来,parse但是如果给它一个明确的签名,您会看到它。
原因是,类似byref结构只分配在堆栈上。但是,F#中的高阶函数使用堆分配。这将是一个矛盾,因此不受支持。