如何在Haskell中简化此操作?

时间:2016-12-07 15:19:23

标签: haskell

我有这样的话:

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,但究竟如何?或....

2 个答案:

答案 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

(我猜的是名字FromSQLSqlData,但这可能大致与你的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,因为,对于您给我们看的所有内容,并不一定是任何一种类型的将映射abc等中的每一个。就此而言,我怀疑在一般情况下是否有任何合理的方法可以简化这一点。