如何用不同的EntityField值概括列表 [英] How to generalize a list with different EntityField values

查看:154
本文介绍了如何用不同的EntityField值概括列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在为例如 /api/v1.0/events?order=-id,title 进行RESTful输出时推广URL处理 - 所以结果将按 id desc和 title asc



排序模型文件:

   - 模型

事件
标题文本
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似乎有两个问题:


  1. 编译器不像 keyVal 那样尽管我将 Asc Desc 赋给了元组,但是第二个值不同
  2. 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:

  1. Compiler doesn't like keyVal as its a list of tuple, where the 2nd value is different
  2. Even though I assign Asc or Desc to direction 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆