3

我对 Haskell 很陌生,目前正在尽我所能防止我的大脑内翻。我有一个以这种方式定义的非常简单的数据库模式:

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
  Instrument
    ticker String
    source String
    exchange String
    deriving Eq Show
|]

我注意到我可以通过以下方式查询表中的所有条目:

getAllInstruments :: (MonadIO m, MonadLogger m) => SqlReadT m [Entity Instrument]
getAllInstruments = select $ from $ \instrument -> do return instrument

但是,如果我只想得到一个列怎么办?我试过这样的事情:

-- doesn't compile
getAllTickers :: (MonadIO m, MonadLogger m) => SqlReadT m [String]
getAllTickers = select $ from $ \instrument -> do return (Value (instrument ^. ticker))

但我收到一条错误消息:

• Couldn't match expected type ‘EntityField val0 typ0’
  with actual type ‘StockPrice -> Ticker’

我在这里找到了关于如何返回列子集的类似问题: Haskell Esqueleto project subset of columns to list of custom records

我的问题是:我是否也需要实现我在我的应用程序中发布的文章中描述的所有类型(即仅针对单个列/字段)?

编辑

感谢提示,我设法想出了以下代码:

getAllTickers' :: (MonadIO m, MonadLogger m) => SqlReadT m [String]
getAllTickers' = do 
  res <- select $ from $ \i -> return (i ^. InstrumentTicker)
  return $ map unValue res

1.)这是可接受的解决方案吗?2.)对于我的教育:有没有办法避免“<-”符号?具体来说,我想知道是否有办法以下列方式编写它:

-- Doesn't compile - need to enter with the map into the m***d - how ?
getAllTickers'' = map unValue (select $ from $ \i -> return (i ^. InstrumentTicker))
4

1 回答 1

1

我对 esqueleto 没有任何经验,但在快速查看教程后,我认为这应该可以工作:

getAllTickers :: (MonadIO m, MonadLogger m) => SqlReadT m [Value String]
getAllTickers = select $ from $ \instrument -> return (instrument ^. InstrumentTicker)

注意不同类型的签名和不同的镜头。希望能帮助到你。

编辑:

我认为unValue您的解决方案没有任何问题,但请不要引用我。如果您想避免 do-notation,其中一种方法是您可以利用 Monad 也是 Functor 的事实,因此您可以使用中缀<$>也称为fmap

getAllTickers' :: (MonadIO m, MonadLogger m) => SqlReadT m [String]
getAllTickers' = 
  map unValue <$> (select $ from $ \i -> return (i ^. InstrumentTicker))
于 2019-10-28T16:52:03.757 回答