如何用不同的EntityField值概括列表 [英] How to generalize a list with different EntityField values
问题描述
我试图在为例如 /api/v1.0/events?order=-id,title
进行RESTful输出时推广URL处理 - 所以结果将按 id
desc和
排序模型文件:
- 模型
事件
标题文本
content Text
userId UserId
导出Eq
导出显示
Haskell file:
- Events.hs
text2Order :: Text - > [SelectOpt Event]
text2Order text =
大小写查找textWithNoPrefix keyVal
只需val - > [direction val]
Nothing - >错误错误的订单
其中
keyVal = [(title,EventTitle)
,(user,EventUserId)
,(id, EventId)
]
textWithNoPrefix = if T.isPrefixOf - text
then T.tail text
else text
direction = if T.isPrefixOf - text
then Desc
else Asc
I似乎有两个问题:
- 编译器不像
keyVal
那样尽管我将Asc
或Desc $>赋给了元组,但是第二个值不同
c $ c>到
方向
编译器不接受它
EventTitle
和 EventUserId
的不同 em>类型,所以你不能把它们放在同一个列表中。但是,您可以在同一列表中放入 EventTitle
和 EventContent
- 它们都有类型 EntityField Event Text
。 然而,类似下面的方法应该可以工作(使用Yesod教程中的Person示例):
makeSelectOpt ::(Char,Char) - > SelectOpt Person
makeSelectOpt('f','+')= Asc PersonFirstName
makeSelectOpt('f',' - ')= Desc PersonFirstName
makeSelectOpt('l','+') = Asc PersonLastName
makeSelectOpt('l',' - ')= Desc PersonFirstName
makeSelectOpt('a','+')= Asc PersonAge
makeSelectOpt('a',' - ' )= Desc PersonAge
makeSelections :: [(Char,Char)] - > [SelectOpt Person]
makeSelections = map makeSelectOpt
您可以将+/-处理像这样:
updown'+'= asc
updown _ = Desc
makeSelectOpt '::(Char,Char) - > SelectOpt Person
makeSelectOpt'('f',dir)= updown dir $ PersonFirstName
makeSelectOpt'('l',dir)= updown dir $ PersonLastName
makeSelectOpt'('a',dir )= updown dir $ PersonAge
如果你想执行错误处理,返回一个可能(SelectOpt Person)
:
makeSelectOpt''::(Char,Char) - > ;也许(SelectOpt Person)
makeSelectOpt''('f',dir)=只需$ updown dir $ PersonFirstName
makeSelectOpt''('l',dir)=只需$ updown dir $ PersonLastName
makeSelectOpt''('a',dir)= Just $ updown dir $ PersonAge
makeSelectOpt''_ = Nothing
然后:
makeSelectOpts'':: [(Char,Char)] - >也许[SelectOpt Person]
makeSelectOpts''pairs = mapM makeSelectOpt''pairs
结果将只要[...]
如果所有对都是有效的,并且没有
,如果其中任何一个都不是' t
$ b
更新
这是另一种使用存在类型的方法,更多类似于你的代码:
$ $ p $ {$#$ $ $ $
$ b $ Apply $ {$# (forall t。EntityField Person t - > SelectOpt Person) - > SelectOpt Person
$ b $ applyToFirstName,applyToLastName,applyToAge :: ApplyToField
applyToFirstName d = d PersonFirstName
applyToLastName d = d PersonFirstName
applyToAge d = d PersonAge
makeSelectOpt'''::(Char,Char) - > SelectOpt Person
makeSelectOpt'''(fld,d)= fn(updown d)
where
table = [('f',applyToFirstName),('l',applyToLastName),( 'a',applyToAge)]
fn =案例查询fld表
只是f - > f
无 - >错误不良现场规格
I try to generalize the URL handling when going to for example /api/v1.0/events?order=-id,title
for a RESTful output - so the results will order by id
desc, and than by title
asc
Models file:
-- models
Event
title Text
content Text
userId UserId
deriving Eq
deriving Show
Haskell file:
-- Events.hs
text2Order :: Text -> [SelectOpt Event]
text2Order text =
case lookup textWithNoPrefix keyVal of
Just val -> [direction val]
Nothing -> error "wrong order"
where
keyVal = [ ("title", EventTitle)
, ("user" , EventUserId)
, ("id" , EventId)
]
textWithNoPrefix = if T.isPrefixOf "-" text
then T.tail text
else text
direction = if T.isPrefixOf "-" text
then Desc
else Asc
I seem to have two problems:
- Compiler doesn't like
keyVal
as its a list of tuple, where the 2nd value is different - Even though I assign
Asc
orDesc
todirection
the complier doesn't accept it
The problem is that EventTitle
and EventUserId
are of different types, so you can't put the two of them in the same list. You can, however, put EventTitle
and EventContent
in the same list -- they both have type EntityField Event Text
.
However, an approach like the following should work (using the Person example from the Yesod tutorial):
makeSelectOpt :: (Char,Char) -> SelectOpt Person
makeSelectOpt ('f','+') = Asc PersonFirstName
makeSelectOpt ('f','-') = Desc PersonFirstName
makeSelectOpt ('l','+') = Asc PersonLastName
makeSelectOpt ('l','-') = Desc PersonFirstName
makeSelectOpt ('a','+') = Asc PersonAge
makeSelectOpt ('a','-') = Desc PersonAge
makeSelections :: [(Char,Char)] -> [SelectOpt Person]
makeSelections = map makeSelectOpt
You can factor out the +/- processing like this:
updown '+' = Asc
updown _ = Desc
makeSelectOpt' :: (Char,Char) -> SelectOpt Person
makeSelectOpt' ('f',dir) = updown dir $ PersonFirstName
makeSelectOpt' ('l',dir) = updown dir $ PersonLastName
makeSelectOpt' ('a',dir) = updown dir $ PersonAge
If you want to perform error processing, return a Maybe (SelectOpt Person)
:
makeSelectOpt'' :: (Char,Char) -> Maybe (SelectOpt Person)
makeSelectOpt'' ('f',dir) = Just $ updown dir $ PersonFirstName
makeSelectOpt'' ('l',dir) = Just $ updown dir $ PersonLastName
makeSelectOpt'' ('a',dir) = Just $ updown dir $ PersonAge
makeSelectOpt'' _ = Nothing
and then:
makeSelectOpts'' :: [(Char,Char)] -> Maybe [SelectOpt Person)
makeSelectOpts'' pairs = mapM makeSelectOpt'' pairs
The result will be Just [...]
if all of the pairs are valid and Nothing
if any one of them isn't recognized.
Update
Here is another approach using existential types which looks a lot more like your code:
{-# LANGUAGE RankNTypes #-}
type ApplyToField = (forall t. EntityField Person t -> SelectOpt Person) -> SelectOpt Person
applyToFirstName, applyToLastName, applyToAge :: ApplyToField
applyToFirstName d = d PersonFirstName
applyToLastName d = d PersonFirstName
applyToAge d = d PersonAge
makeSelectOpt''' :: (Char,Char) -> SelectOpt Person
makeSelectOpt''' (fld,d) = fn (updown d)
where
table = [ ('f',applyToFirstName), ('l',applyToLastName), ('a',applyToAge) ]
fn = case lookup fld table of
Just f -> f
Nothing -> error "bad field spec"
这篇关于如何用不同的EntityField值概括列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!