Алекс требует, чтобы тип токена результата был некоторой функцией, которая принимает AlexPosn.

Я пытаюсь написать лексер, который лексирует комментарии в стиле c и ничего больше (пока).

{
module Lexer where

import Prelude hiding (head, take, tail)
import Data.ByteString.Lazy
}

%wrapper "monad-bytestring"

@not_bc_end = ~\* | \* ~\/


tl :-
  <0>   $white+             ;
  <0>   "/*"                { tok (\p s -> BCBegin p) `andBegin` bc }
  <bc>  .+ / not_bc_end     { tok (\p s -> BCContent p s) }
  <bc>  "*/"                { tok (\p s -> BCEnd p) `andBegin` 0 }
  <0>   "//"                { tok (\p s -> LCBegin p) `andBegin` lc }
  <lc>  .*$                 { tok (\p s -> LCContent p s) }

{
tok :: (AlexPosn -> ByteString -> Token) -> AlexInput -> Int64 -> Alex Token
tok f (p, _, bs, _) len = pure $ f p (take len bs)

data Token
  = LCBegin AlexPosn
  | LCContent AlexPosn ByteString
  | BCBegin AlexPosn
  | BCEnd AlexPosn
  | BCContent AlexPosn ByteString
  | End AlexPosn

alexEOF = pure End
}

Генерация кода прошла успешно, но компиляция завершилась со следующей ошибкой:

templates/wrappers.hs:288:9: error:
    • Couldn't match type ‘Token’ with ‘AlexPosn -> Token’
      Expected type: Alex (AlexPosn -> Token)
        Actual type: Alex Token
    • In a stmt of a 'do' block: action (ignorePendingBytes inp__) len
      In the expression:
        do alexSetInput inp__'
           action (ignorePendingBytes inp__) len
      In the expression:
        let len = n' - n
        in
          do alexSetInput inp__'
             action (ignorePendingBytes inp__) len

Компилятор жалуется, что тип токена (обернутый в Alex) должен принимать аргумент типа AlexPosn. Я запутался, потому что в AlexInput уже есть AlexPosn, а в руководстве пользователя прямо указано, что тип токена может быть любым, если они остаются одинаковыми для всех токенов.

Изменение определения tok на следующее решило проблему:

tok :: (AlexPosn -> ByteString -> Token) -> AlexInput -> Int64 -> Alex (AlexPron -> Token)
tok f (_, _, bs, _) len = pure $ \p -> f p (take len bs)

Но я понятия не имею, почему Алекс использует токен, чтобы взять AlexPosn


person Poscat    schedule 24.03.2020    source источник


Ответы (1)


Я случайно добавил поле типа AlexPosn в конструктор End

person Poscat    schedule 24.03.2020