我正在尝试使用Span实现二进制解析器组合器库。我不确定这是否真的是个好主意,我只是想了解更多有关这两者的信息。
前段时间,我已经使用parser combinators编写了一个小型的二进制解析器,该解析器运行良好。
代码如下:
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
...
我尝试使用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
我在map
行的match parser bytes with
函数中收到以下错误:
错误FS0418:此时无法使用byref类型的值'bytes'
这是什么意思?为什么我不能在这里使用Span?有人尝试过使用Span实现解析器组合器吗?您将如何解决这个问题?
谢谢。
答案 0 :(得分:0)
不支持这种模式(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
一种简单的形式:
let foo (f: Span<int> -> int) (x: Span<int>) = f x
也给出f
的错误。有一些与byref
相似的类型和类型缩写的细微之处,它们掩盖了parse
上的错误,但是如果给它一个明确的签名,您会看到它。
原因是类似byref
的结构仅分配在堆栈上。但是,F#中的高阶函数使用堆分配。这将是一个矛盾,因此不支持。