使用数据构造函数筛选表



我正在努力学习Haskell,但我不知道如何从这里继续。我在下面添加了代码中重要的部分。因此,我定义了一个具有多个值的Query,最后一个值被卡住了——在特定条件之后过滤表中的行。因此例如它过滤只具有列"0"的行;最终等级">5.我在每一行上使用FilterOp来查看是否可以保留它,而我的表中只有StringsFloats,所以我为每一行创建了一个实例。在完成条件之后,我必须为数据构造函数编写评估,但我也不确定该部分是否正确。输入将类似于以下内容:Filter (Gt "Final grade" (read "5" :: Float)) (FromCSV example_csv)

type CSV = String
type Table = [[String]]
data Query = FromCSV CSV
| ToCSV Query
...
| forall a. FEval a => Filter (FilterCondition a) Query
data FilterCondition a =
Eq String a |
Lt String a |
Gt String a
type FilterOp = Row -> Bool
class FEval a where
feval :: [String] -> (FilterCondition a) -> FilterOp
-- This is what I have to do
instance FEval Float where
...
instance FEval String where
...
-- I'm not sure this is right
instance Filter (FilterCondition a) Query where
...

很难给你具体的建议,但这个问题很有趣,所以我决定向你展示我认为与你的问题接近的东西:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
module Main where
import Data.List (intercalate)
main :: IO ()
main = putStrLn $ query exampleQuery
----------------------------------------------------------------------
-- Example
exampleCSV :: CSV
exampleCSV = "Name,GradenBob,5nJill,2nSandy,1"
-- > query exampleQuery
-- "Name,GradenJill,2nSandy,1n"
exampleQuery :: Query CSV
exampleQuery = ToCSV $ Filter (Lt "Grade" (5 :: Int)) $ FromCSV exampleCSV
----------------------------------------------------------------------
-- Types
-- | Query - a = result-type
data Query a where
-- | query to turn a CSV into a table
FromCSV :: CSV -> Query Table 
-- | query to turn a table into a CSV
ToCSV :: Query Table -> Query CSV
-- | query to filter a table given a filter-condition
Filter :: forall a. TableFilter a => FilterCondition a -> Query Table -> Query Table
type CSV = String
-- | Table holds rows (= list of values) and a list of column-names
data Table = Table [Row] [Column]
type Column = String
type Row = [String]
class TableFilter a where
filterRow :: FilterCondition a -> [Column] -> Row -> Bool
data FilterCondition a 
= Eq Column a
| Lt Column a
| Gt Column a
----------------------------------------------------------------------
-- Query
query :: Query a -> a
query (FromCSV csv) = fromCSV csv
query (ToCSV tableQuery) = toCSV (query tableQuery)
query (Filter cond tableQuery) = applyFilter cond (query tableQuery)
applyFilter :: TableFilter a => FilterCondition a -> Table -> Table
applyFilter cond (Table rows cols) = Table rows' cols
where rows' = filter (filterRow cond cols) rows
fromCSV :: CSV -> Table
fromCSV = go . lines
where
go [] = error "cannot parse empty CSV - at least a header-line is needed"
go [cols] = Table [] (splitOn ',' cols)
go (cols:tbl) = Table rs cs
where
rs = map (splitOn ',') tbl
cs = splitOn ',' cols
toCSV :: Table -> CSV
toCSV (Table rs cs) = 
unlines $ intercalate "," cs : map (intercalate ",") rs
----------------------------------------------------------------------
-- TableFilter instances
instance TableFilter Int where
filterRow = genFilterRow
instance TableFilter Float where
filterRow = genFilterRow
genFilterRow :: (Ord a, Read a) => FilterCondition a -> [Column] -> Row -> Bool
genFilterRow cond cols row = 
and $ zipWith (checkCond cond) cols row
where
checkCond (Eq condCol condVal) col val = condCol /= col || condVal == read val
checkCond (Lt condCol condVal) col val = condCol /= col || condVal > read val
checkCond (Gt condCol condVal) col val = condCol /= col || condVal < read val
----------------------------------------------------------------------
-- helpers
splitOn :: Eq a => a -> [a] -> [[a]]
splitOn c = go c []
where
go _ acc [] = [reverse acc]
go c acc (y:ys)
| c == y = reverse acc : go c [] ys
| otherwise = go c (y:acc) ys

真正的问题本身可能编码在genFilterRow中——我不得不进行一些猜测,但我认为您描述中的[String]参数实际上是列名。因此,这只是用行值压缩它们,然后将FilterConditionread一起使用来过滤匹配的列名。


我不知道您期望的输出,所以我使用GADT为不同的Querys获得不同的输出(并且无法执行类似Filter (Lt "Grade" (5 :: Int)) $ ToCSV $ FromCSV exampleCSV的操作(。

实际的过滤可以相当于通用(genFilterRow=gen,意思是普通(-不想使用不可判定的实例,所以我认为使用这个助手和简单的instance FilterTable是一个很好的折衷方案。

最新更新