首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从自由的可选函式生成opt解析式应用分析器

从自由的可选函式生成opt解析式应用分析器
EN

Stack Overflow用户
提问于 2014-11-03 16:23:03
回答 1查看 334关注 0票数 18

考虑以下类型的签名:

代码语言:javascript
复制
data Foo x = Foo {
    name :: String
  , reader :: String -> x
}

instance Functor Foo where
  fmap f (Foo n r) = Foo n $ f . r

现在,我展示了从Foooptparse-applicativeParser类型的自然转换:

代码语言:javascript
复制
import qualified Options.Applicative as CL

mkParser :: Foo a -> CL.Parser a
mkParser (Foo n _) = CL.option CL.disabled ( CL.long n )

(好吧,这有点没用,但可以供讨论)。

现在我把Bar作为Foo上的自由可选函子。

代码语言:javascript
复制
type Bar a = Alt Foo a

考虑到这是一个自由函子,我应该能够将mkParser提升到从BarParser的自然转换。

代码语言:javascript
复制
foo :: String -> (String -> x) -> Bar x
foo n r = liftAlt $ Foo n r

myFoo :: Bar [String]
myFoo = many $ foo "Hello" (\_ -> "Hello")

clFoo :: CL.Parser [String]
clFoo = runAlt mkParser $ myFoo

实际上,这是可行的,并给了我一个Parser。然而,这是一个非常无用的方法,因为尝试用它做很多事情会导致无限循环。例如,如果我试图描述它:

代码语言:javascript
复制
CL.cmdDesc clFoo
> Chunk {unChunk = 

挂着直到被打断。

原因似乎是optparse-applicative 骗子在其对manysome的定义中:它在幕后使用一元解析。

我在这里做错什么了吗?考虑到这一点,我不知道如何以这种方式构造解析器。有什么想法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-02-24 19:44:40

正如注释中所指出的,您必须显式地处理many。从Earley复制的方法

代码语言:javascript
复制
#!/usr/bin/env stack
-- stack --resolver=lts-5.3 runghc --package optparse-applicative
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}

import Control.Applicative
import qualified Options.Applicative as CL
import qualified Options.Applicative.Help.Core as CL

data Alt f a where
  Pure   :: a                             -> Alt f a
  Ap     :: f a       -> Alt f (a -> b)   -> Alt f b
  Alt    :: [Alt f a] -> Alt f (a -> b)   -> Alt f b
  Many   :: Alt f a   -> Alt f ([a] -> b) -> Alt f b

instance Functor (Alt f) where
  fmap f (Pure x)   = Pure $ f x
  fmap f (Ap x g)   = Ap x $ fmap (f .) g
  fmap f (Alt x g)  = Alt x $ fmap (f .) g
  fmap f (Many x g) = Many x $ fmap (f .) g

instance Applicative (Alt f) where
  pure = Pure

  Pure f   <*> y = fmap f y
  Ap x f   <*> y = Ap x $ flip <$> f <*> y
  Alt xs f <*> y = Alt xs $ flip <$> f <*> y
  Many x f <*> y = Many x $ flip <$> f <*> y

instance Alternative (Alt f) where
  empty = Alt [] (pure id)
  a <|> b = Alt [a, b] (pure id)
  many x  = Many x (pure id)

-- | Given a natural transformation from @f@ to @g@, this gives a canonical monoidal natural transformation from @'Alt' f@ to @g@.
runAlt :: forall f g a. Alternative g => (forall x. f x -> g x) -> Alt f a -> g a
runAlt u = go where
    go :: forall b. Alt f b -> g b
    go (Pure x)    = pure x
    go (Ap x f)    = flip id <$> u x                           <*> go f
    go (Alt xs f)  = flip id <$> foldr (<|>) empty (map go xs) <*> go f
    go (Many x f)  = flip id <$> many (go x)                   <*> go f

-- | A version of 'lift' that can be used with just a 'Functor' for @f@.
liftAlt :: (Functor f) => f a -> Alt f a
liftAlt x = Ap x (Pure id)

mkParser :: Foo a -> CL.Parser a
mkParser (Foo n r) = CL.option (CL.eitherReader $ Right . r) ( CL.long n CL.<> CL.help n )

data Foo x = Foo {
    name :: String
  , reader :: String -> x
}

instance Functor Foo where
  fmap f (Foo n r) = Foo n $ f . r

type Bar a = Alt Foo a

foo :: String -> (String -> x) -> Bar x
foo n r = liftAlt $ Foo n r

myFoo :: Bar [String]
myFoo = many $ foo "Hello" (\_ -> "Hello")

clFoo :: CL.Parser [String]
clFoo = runAlt mkParser $ myFoo

main :: IO ()
main = do
  print $ CL.cmdDesc clFoo
  print $ CL.cmdDesc $ mkParser (Foo "Hello" $ \_ -> "Hello")
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26718443

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档