我有这样的话:
func1 :: IO [MyObjectData]
func1 = do
res1 <- quickQuery conn123 "select * from table1" []
return $ map parseMyObjectData res1
where
parseMyObjectData [a, b, c, d, e, f, g, h, i, j, k, l] =
MyObjectData (fromSql a) (fromSql b) (fromSql c) (fromSql d) (fromSql e)
(fromSql f) (fromSql g) (fromSql h) (fromSql i)
(MyObjectDataNested
(fromSql j) (fromSql k) (fromSql l))
它是一个简化版本。有没有办法简化它?我以为我应该以某种方式使用&#34; fromSql&#34;在地图或mapM,但究竟如何?或....
答案 0 :(得分:1)
不是真的。你可能会混淆data generics,这是一个大锤,除非你为许多数据类型这样做。如果它只是一个或两个实例,我只是咬紧牙关并写出样板。如果您有这样的大架构,那么值得阅读Scrap Your Boilerplate论文并使用泛型。 (N.B.可能有更现代的仿制药方法,我不确定,这是我用过的唯一一种方法)
根据您决定数据库抽象的工作方式,有“更清洁”的方法。如果要将列视为“串行流”,则可以为可反序列化的对象创建一个类:
import Control.Monad.Supply
class FromSQLStream a where
fromSQLStream :: Supply SqlData a
-- All FromSQLs are FromSQLStreams, but a superclass isn't a good idea
-- for some reasons here...
fromSqlS :: (FromSQL a) => Supply SqlData a
fromSqlS = fromSql <$> supply
(我猜的是名字FromSQL
和SqlData
,但这可能大致与你的SQL库有关。
然后至少它构成了一点:
instance FromSQLStream MyObjectDataNested where
fromSQLStream = MyObjectDataNested <$> fromSqlS <*> fromSqlS <*> fromSqlS
instance FromSQLStream MyObjectData where
fromSqlStream =
MyObjectData <$> fromSqlS <*> fromSqlS <*> fromSqlS <*> fromSqlS
<*> fromSqlS <*> fromSqlS <*> fromSqlS <*> fromSqlS
<*> fromSqlS <*> fromSQLStream
这是可怕的重复,但由于在指导事物周围浮动的类型信息,它的重复性低于它的外观。但是,如果没有仿制药,我认为你不能做得更好。
答案 1 :(得分:0)
您很可能既不使用map
也不使用mapM
,因为,对于您给我们看的所有内容,并不一定是任何一种类型的将映射a
,b
,c
等中的每一个。就此而言,我怀疑在一般情况下是否有任何合理的方法可以简化这一点。