8

私はAlexを学び始めており、ステートフル コンテキストが役立つところまで到達したと信じていますが、どうすればよいか完全にはわかりません。私はerlang バイナリの限られたサブセットをレックスしようとしています。次のレクサーを使用します。

{
module Main (main, Token(..), AlexPosn(..), alexScanTokens, token_posn) where
}

%wrapper "posn"

$digit = 0-9      -- digits                                                                            
$alpha = [a-zA-Z] -- alphabetic characters                                                             
$dbl_quote = \"

tokens :-

  $white+                        ;
  ","                            { tok (\p s -> Comma p) }
  "<<"                           { tok (\p s -> BinaryOpen p) }
  ">>"                           { tok (\p s -> BinaryClose p) }
  $dbl_quote [^$dbl_quote]* $dbl_quote { tok (\p s -> ErlStr p (init (tail s))) }
  $digit+                        { tok (\p s -> ErlInt p (read s)) }

{
-- action helpers:                                                                                     
tok :: (AlexPosn -> String -> Token) -> AlexPosn -> String -> Token
tok f p s = f p s

data Token =
  Comma       AlexPosn |
  BinaryOpen  AlexPosn |
  BinaryClose AlexPosn |
  ErlInt   AlexPosn Integer |
  ErlStr   AlexPosn String
  deriving (Eq, Show)

token_posn :: Token -> AlexPosn
token_posn (Comma    p) = p
token_posn (BinaryOpen  p) = p
token_posn (BinaryClose p) = p
token_posn (ErlInt   p _) = p
token_posn (ErlStr   p _) = p

main :: IO ()
main = do
  s <- getContents
  print (alexScanTokens s)
}

私はかなりうまくやっています。例えば、

> alex so_erlang_lexer.x  && ghc --make -o erlexer so_erlang_lexer.hs && echo '<<"100", 1>>' | ./erlexer 
[1 of 1] Compiling Main             ( so_erlang_lexer.hs, so_erlang_lexer.o )
Linking erlexer ...
[BinaryOpen (AlexPn 0 1 1),ErlStr (AlexPn 2 1 3) "100",Comma (AlexPn 7 1 8),ErlInt (AlexPn 9 1 10) 1,BinaryClose (AlexPn 10 1 11)]

lexed return を と同等にしたいBinary [ErlStr "100", ErlInt 1]のですが、頭の中でクリックする開始コードを使用するレクサーを見つけることができませんでした。

  • ここで参照されているGHC の字句解析器は、Alex ラッパーを一切使用していません。
  • モナドと monadUserState ラッパーに関する Alex 自身のドキュメント (こちら) を見ると、どちらを選択すればよいか、またどちらをどのように利用できるかがわかりません。
  • アレックスのの例が最も有望ですが、あまりにも大きいので、私の無知を片付けるのに苦労しています.
  • この質問はモナドパーサーを利用していますが、その状態機能を利用していないようです。

誰かが私を少し案内してくれるほど親切でしょうか?

4

1 に答える 1

4

あなたがレクサーで何をしようとしているのか正確にはわかりませんが、これについてガイドするのに十分な知識があります(ただし、役に立たないトークンをフィルター処理するだけでよい場合は、アレックスのモナドインターフェイスはやり過ぎのようです)。とにかく、AlexUserState蓄積するために使用するサンプルコードを次に示します「monadUserState」ラッパーで選択されたトークン。



{
module Main (main) where
}

%wrapper "monadUserState"

$digit = 0-9      -- digits                                                                            
$alpha = [a-zA-Z] -- alphabetic characters                                                             
$dbl_quote = \"

tokens :-

  $white+                              ;
  ","                                  { ignoreToken  }
  ">"                                 { ignoreToken }
  $dbl_quote [^$dbl_quote]* $dbl_quote { pushToken  $ ErlStr . init . tail  }
  $digit+                              { pushToken  $ ErlInt . read }

{

alexEOF :: Alex ()
alexEOF = return ()

-- some useful interaces to the Alex monad (which is naturally an instance of state monad)
modifyUserState :: (AlexUserState -> AlexUserState) -> Alex ()
modifyUserState f = Alex (\s -> let st = alex_ust s in Right (s {alex_ust = f st},()))

getUserState ::  Alex AlexUserState
getUserState = Alex (\s -> Right (s,alex_ust s))

-- Token definition minus position information for simplicity
data Token =
  Comma        |
  BinaryOpen   |
  BinaryClose  |
  ErlInt    Integer |
  ErlStr    String
  deriving (Eq, Show)

newtype AlexUserState = Binary [Token]
  deriving (Eq, Show)

alexInitUserState :: AlexUserState
alexInitUserState = Binary []


-- action helpers:                                                                                     
pushToken :: (String -> Token) -> AlexAction ()
pushToken tokenizer = 
  \(posn,prevChar,pending,s) len -> modifyUserState (push $ take len s) >> alexMonadScan
    where
       -- Here tokens are accumulated in reverse order for efficiency.
       -- You need a more powerful data structure like Data.Sequence to preserve the order.
       push :: String -> AlexUserState -> AlexUserState
       push s (Binary ts) = Binary (tokenizer s : ts) 

ignoreToken :: AlexAction ()
ignoreToken _ _   = alexMonadScan


runAlexScan :: String -> Either String AlexUserState
runAlexScan s = runAlex s $ alexMonadScan >> getUserState


main :: IO ()
main = getContents >>= print . runAlexScan

}

しかし、主な問題は、Haskell でのモナドの概念と使用法にまだ十分に慣れていないように見えることだと思います。Alex のモナド インターフェイスは、実際には非常に自然であり、状態モナドの典型であり、コーディングの経験があれば、生成されたコードをざっと見ただけで簡単に推測できるものです。(推測が間違っていたとしても、型チェッカーはおそらく関連するエラーを見つけます。)

これについては、モナドに関する質の高い質問と回答が数多くあるように思われるので、Real World Haskellを参照してください(プロファイリングに関する章が特に役に立ちました)。

しかし、たまたま圏論についてある程度の知識がある場合、おそらくモナドを学ぶ最も速い方法は、いくつかの関連する論文に直接飛び込むことです (また、圏論におけるモナドは、群の作用のように、作用の一般化であることを思い出してください。これについては、モナドとアローに関するこの論文のリストを参照してください。 これには、技術的な背景を持つ人向けの入門論文とチュートリアルが含まれています。

ところで、私はErlangを学び始めたばかりです。それについて少しご案内いただけますか?静的型付けの欠如に悩まされていませんか? cloud-haskell を試して Erlang と比較しましたか? また、分散プログラミングのコンテキストで最も生産性が高いと感じる言語はどれですか?

于 2012-10-06T09:17:21.903 に答える