我是来自Scala的Haskell的新手。我喜欢Haskell,但在使用persistent
时,我觉得我正在打击类型系统。
我的请求:我想将一些插入逻辑分离到自己的方法中。我无法弄清楚这些类型或正确的方法。我所有失败的尝试都无法编译。下面有更简洁的问题。
这是数据声明:
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Curator
name String
url String
feed String
UniqueUrl url
deriving Show
Article
url String
title String
content String
curatorId CuratorId Eq
deriving Show
|]
这是一次尝试失败的尝试:
insertArticle :: String -> String -> String -> MaybeT (???)
insertArticle url title content = do
curatorId <- selectFirst [curatorName ==. "Fake Name"]
lift $ do
curator <- curatorId
insert (Article url title content curator)
所以,我的问题:
???
应该包含哪些类型? lift
是否在正确的位置? (通常编译器更有用)。 PS - 我已经成功地抽象出其他逻辑,例如插入物只会让我感到痛苦。使用SqlPersistM
getFeeds :: SqlPersistM [Curator]
getFeeds = do
curatorIds <- selectList [] [Asc CuratorName]
let curatorGenerics = map entityVal curatorIds
let curators = map (\x -> x :: Curator) curatorGenerics
return curators
答案 0 :(得分:1)
insertArticle
的返回类型应为SqlPersistM (Maybe ArticleId)
,因为它会在Just
monad中返回Nothing
插入的文章ID或SqlPersistM
。
您可以实现以下功能:
insertArticle :: String -> String -> String -> SqlPersistM (Maybe ArticleId)
insertArticle url title content = do
curatorEntity <- selectFirst [CuratorName ==. "Fake Name"] []
for curatorEntity $ \(Entity curatorId _) ->
insert (Article url title content curatorId)
我使用for
中的Data.Traversable
来处理Maybe
值selectFirst
返回此处。
但实际上,我不喜欢这种类型的签名,因为它坚持使用sql后端。为了使其更通用,您可以编写类似这样的类型注释。
insertArticle :: (Applicative m, PersistQuery m, PersistMonadBackend m ~ PersistEntityBackend Curator) =>
String -> String -> String -> m (Maybe ArticleId)
签名有点复杂,但此功能适用于任何后端。
顺便说一下,您的getFeeds
可以简化。
getFeeds :: (Functor m, PersistQuery m, PersistMonadBackend m ~ PersistEntityBackend Curator) =>
m [Curator]
getFeeds = map entityVal <$> selectList [] [Asc CuratorName]