我试图解析09/10/2015 17:20:52
:
{-# LANGUAGE FlexibleContexts #-}
import Text.Parsec
import Text.Parsec.String
import Text.Read
import Control.Applicative hiding (many, (<|>))
data Day = Day
{ mo :: Int
, dy :: Int
, yr :: Int
} deriving (Show)
data Time = Time
{ hr :: Int
, min :: Int
, sec :: Int
} deriving (Show)
day = listUncurry Day <$> (sepCount 3 (char '/') $ read <$> many digit)
time = listUncurry Time <$> (sepCount 3 (char ':') $ dign 2 )
dign :: (Stream s m Char, Read b) => Int -> ParsecT s u m b
dign = (read <$>) . flip count digit
-- how generalize to n?
listUncurry h [x1,x2,x3] = h x1 x2 x3
sepCount n sep p = (:) <$> p <*> (count (n-1) $ sep *> p)
我预感到某种zipWithN
会概括listUncurry
。也许某种foldl ($)
?
作为一个附带问题(出于好奇心),可以生成parsec
解析器吗?
答案 0 :(得分:7)
实际上,您只需要Functor
:
listUncurry :: Functor f => (a -> a -> a -> r) -> f [a] -> f r
listUncurry h p =
(\[x, y, z] -> h x y z) <$> p
对我来说,只有Functor
是必要的提示就是你有这样的代码模式:
do x <- m
return (f ...)
这相当于
m >>= (\x -> return (f ...))
与
相同fmap (\x -> f ...) m
这是因为monad法律imply this identity:
fmap f xs = xs >>= return . f
listUncurry
我在大多数情况下都不建议这样做,因为它会将编译时错误转换为运行时错误,但这就是你实现多变量listUncurry
的方法:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
class ListUncurry a x r where
listUncurry :: a -> [x] -> r
instance ListUncurry k a r => ListUncurry (a -> k) a r where
listUncurry f (x:xs) = listUncurry (f x) xs
listUncurry _ _ = error "listUncurry: Too few arguments given"
instance ListUncurry r a r where
listUncurry r [] = r
listUncurry _ _ = error "listUncurry: Too many arguments given"
如果您也使用它,则需要大量显式类型注释。可能有一种方法可以使用类型族或函数依赖来帮助解决这个问题,但我现在无法想到这一点。由于这可能是可解决的(至少在某种程度上),在我看来,更大的问题是类型错误从编译时错误变为运行时错误。
样本用法:
ghci> listUncurry ord ['a'] :: Int
97
ghci> listUncurry ((==) :: Int -> Int -> Bool) [1,5::Int] :: Bool
False
ghci> listUncurry ((==) :: Char -> Char -> Bool) ['a'] :: Bool
*** Exception: listUncurry: Too few arguments given
ghci> listUncurry ((==) :: Char -> Char -> Bool) ['a','b','c'] :: Bool
*** Exception: listUncurry: Too many arguments given
listUncurry
如果您将课程更改为
class ListUncurry a x r where
listUncurry :: a -> [x] -> Maybe r
并适当地更改实例中的错误情况,您至少会获得一个更好的界面来处理错误。如果您想保留该信息,也可以使用区分“太多”和“太少”参数错误的类型替换Maybe
。
虽然您需要添加更多错误处理(Maybe
的{{1}},Functor
和{{1},但我认为这会更好一些方法。接口将使这个相当不错。)
最终取决于这将代表什么样的错误。如果程序执行不能再以任何有意义的方式继续,如果它遇到这样的错误,那么第一种方法(或类似的方法)可能比第二种方法更合适。如果有任何方式从错误中恢复,第二种方法将优于第一种方法。
首先应该使用多变量技术是一个不同的问题。重构程序可能会更好,以避免多变量材料的额外复杂性。
答案 1 :(得分:2)
我也确定我不应该
oneElement
列表 - 这样做的正确方法是什么?
otherElement
的以下实施更有效:
snoc