我定义了以下数据类型
data EventType = RUN_EVENT Integer | GIVE_ITEM Integer Integer ... deriving (Show)
从某些测试中,我检索数据如下
[&#34; EVENT&#34;&#34; 6001&#34;&#34; E&#34;&#34; RUN_EVENT&#34;&#34; 6010&#34;] < / p>
当我处理数据时,例如,在&#34; E&#34;之后,我得到&#34; RUN_EVENT&#34;,我想构建类型为 EventType <的数据/ em>具有值 RUN_EVENT 6010 。
要做到这一点,我可以创建一个巨大的列表,基本上说如果我面对&#34; RUN_EVENT&#34;然后构造一个值为 RUN_EVENT 的值,但这不会有效,所以有没有办法转换&#34; RUN_EVENT&#34;到术语 RUN_EVENT ,以便我可以将其用作
exec = (stringToTerm "RUN_EVENT") 6010
答案 0 :(得分:3)
使用Read
import Text.Read (readMaybe)
data EventType = RUN_EVENT Integer | GIVE_ITEM Integer Integer ...
deriving (Read, Show)
parseChunk :: [String] -> Maybe EventType
parseChunk = readMaybe . unwords
这将像
一样工作parseChunk ["RUN_EVENT","4"] --> Just (RUN_EVENT 4)
parseChunk ["GIVE_ITEM","1","2"] --> Just (GIVE_ITEM 1 2)
parseChunk ["RUN_EVENT","4","5"] --> Nothing -- too many arguments
它是hacky的原因是它依赖于字符串操作将数据流转换为Haskell表达式(read
解析)。如果你的解析器的复杂性增加,那么这种方法可能会崩溃,或者它的黑客可能会失控。想象一下,你的一个构造函数需要一个列表,然后你必须在"["
之前开始将","
和read
插入到流中。
如果你想要更多的控制,更好的方法是编写一个合适的解析器,可能使用Parsec或其类似的。但您必须手动列出所有案例或使用generics生成案例。我自己的美学将允许read
解决方案现在代表,但如果看起来它变得一团糟,那么就转换到正式的解析器。
答案 1 :(得分:1)
从Read类中派生您的数据。然后按如下方式定义函数
data EventType = RUN_EVENT Integer | GIVE_ITEM Integer Integer ... deriving (Show, Read)
stringToTerm :: String -> Integer -> EventType
stringToTerm stringEvent n = read $ stringEvent ++ " " ++ show n
请记住,由于读取实例,类型注释很重要。函数stringToTerm可以部分应用于获得你想要的东西
此致
答案 2 :(得分:0)
Hacky解决方案,-XViewPatterns
增加了清晰度
stringToTerm [] = []
stringToTerm ("EVENT":(read -> num):xs) = EVENT num : stringToTerm xs
stringToTerm ("RUN_EVENT":(read -> num1):(read -> num2):xs) = RUN_EVENT num1 num2 : stringToTerm xs
这样你就不会写一个真正的解析器,从而省去了麻烦,但如果数据不正确就会爆炸
答案 3 :(得分:0)
直接实施您的问题可能是:
parseEventType :: [String] -> EventType
parseEventType ["EVENT", _, _, "RUN_EVENT", i] = RUN_EVENT (read i)
parseEventType ["EVENT", i, _, "GIVE_ITEM", j] = GIVE_ITEM (read i) (read j)
parseEventType x = error ("parseEventType: could not parse " ++ show x)
GIVE_ITEM案例可能不正确,但应该给你一个想法。
但是,这有一些问题,主要是在错误处理方面:如果参数不是整数,或者列表的形状与您的某个类型不匹配,您会怎么做?最简单的方法是使用Maybe
:
parseEventType :: [String] -> Maybe EventType
parseEventType ["EVENT", _, _, "RUN_EVENT", i] = RUN_EVENT <$> readMay i
parseEventType ["EVENT", i, _, "GIVE_ITEM", j] = GIVE_ITEM <$> readMay i <*> readMay j
parseEventType x = Nothing
这显示了适用的风格。