gpt4 book ai didi

haskell - 使用 Parsec 将字符串映射到数据类型的紧凑方法

转载 作者:行者123 更新时间:2023-12-02 02:50:44 25 4
gpt4 key购买 nike

我似乎经常遇到将关键字直接映射到数据类型的情况,我如下解决了它。它很快就会失控,因为您必须重复字符串值。

有没有更紧凑的方式来表达这一点?

import Text.ParserCombinators.Parsec

data Keyword = Apple | Banana | Cantaloupe

parseKeyword :: Parser Keyword
parseKeyword = ( string "apple"
<|> string "banana"
<|> string "cantaloupe"
) >>= return . strToKeyword
where strToKeyword str = case str of
"apple" -> Apple
"banana" -> Banana
"cantaloupe" -> Cantaloupe

编辑:

作为后续问题,因为这似乎太容易了。紧凑型解决方案如何与 try 一起使用?

例如。
import Text.ParserCombinators.Parsec

data Keyword = Apple | Apricot | Banana | Cantaloupe

parseKeyword :: Parser Keyword
parseKeyword = ( try (string "apple")
<|> string "apricot"
<|> string "banana"
<|> string "cantaloupe"
) >>= return . strToKeyword
where strToKeyword str = case str of
"apple" -> Apple
"apricot" -> Apricot
"banana" -> Banana
"cantaloupe" -> Cantaloupe

最佳答案

如果你只是想避免一些重复,你可以使用 (<$) 运算符(operator):

import Text.ParserCombinators.Parsec
import Control.Applicative ((<$))

data Keyword = Apple | Banana | Cantaloupe

parseKeyword :: Parser Keyword
parseKeyword
= Apple <$ string "apple"
<|> Banana <$ string "banana"
<|> Cantaloupe <$ string "cantaloupe"

也可以使用 GHC.Generics 为任何只有单元构造函数的类型创建一个完全通用的解决方案。 :
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}

import Text.ParserCombinators.Parsec
import Control.Applicative ((<*))
import Data.Char (toLower)
import GHC.Generics

class GParse f where
gParse :: Parser (f a)

instance (GParse f, Constructor c) => GParse (C1 c f) where
gParse = fmap M1 gParse <* string (map toLower $ conName (undefined :: t c f a))

instance GParse f => GParse (D1 c f) where
gParse = fmap M1 gParse

instance (GParse a, GParse b) => GParse (a :+: b) where
gParse = try (fmap L1 gParse) <|> fmap R1 gParse

instance GParse U1 where
gParse = return U1

genericParser :: (Generic g, GParse (Rep g)) => Parser g
genericParser = fmap to gParse

这是相当多的样板文件,但现在您可以为任何兼容类型创建解析器,只需:
{-# LANGUAGE DeriveGeneric #-}

data Keyword = Apricot | Apple | Banana | Cantaloupe deriving (Show, Generic)

parseKeyword :: Parser Keyword
parseKeyword = genericParser

在 GHCI 中测试:
> parseTest parseKeyword "apple"
Apple
> parseTest parseKeyword "apricot"
Apricot
> parseTest parseKeyword "banana"
Banana

处理多字构造函数,如 RedApple只是为 "RedApple" 编写字符串翻译函数的问题-> "red_apple"并在 C1 中使用它实例。 IE。
import Data.List (intercalate)
import Data.Char (toLower, isLower)

mapName :: String -> String
mapName = intercalate "_" . splitCapWords where
splitCapWords "" = []
splitCapWords (x:xs) =
let (word, rest) = span isLower xs
in (toLower x : word) : splitCapWords rest

instance (GParse f, Constructor c) => GParse (C1 c f) where
gParse = fmap M1 gParse <* string (mapName $ conName (undefined :: t c f a))

关于haskell - 使用 Parsec 将字符串映射到数据类型的紧凑方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25215184/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com