如何为所有列创建一个通用排序选项SelectOpt?

时间:2014-04-13 15:37:14

标签: haskell yesod persistent

是否有更优雅的写作方式:(下面的代码编译)

getModelSorterOpt sortOrder sortField = do
    case sortOrder of
        "Asc" ->
            case sortField of
                "id" -> Just   $ Asc ModelId
                "name" -> Just $ Asc ModelName
                "created" -> Just $ Asc ModelCreated
                _ -> Nothing
        "Desc" ->
            case sortField of                                                                                                    
                "id" -> Just   $ Desc ModelId
                "name" -> Just $ Desc ModelName
                "created" -> Just $ Desc ModelCreated
                _ -> Nothing

主要问题是我不能使用变量而不是“Asc / Desc”情况。像下面的代码一样,未能进行类型检查。

getModelSorterOpt sortOrder sortField = 
                case sortField of                                                                                                    
                    "id" -> Just   $ sortOrder' ModelId
                    "name" -> Just $ sortOrder' ModelName
                    "created" -> Just $ sortOrder' ModelCreated
                    _ -> Nothing
                where sortOrder' = case sortOrder of 
                    "Asc" -> Asc
                    "Desc" -> Desc

GHC表示,它不希望ModelId和ModelName成为同一案例的一部分,因为它们是不同的类型。我认为这是有效的。但是,Asc ModelIdAsc ModelName的类型相同。我如何告诉GHC?


哈马尔的初步答案有效。此版本仍无效:

getModelSorterOpt sortOrder sortField = do
        (sortOrder'' ::  EntityField Model a -> SelectOpt Model ) <- sortOrder'
        case sortField of                                                                                                        
            "id" -> Just   $    sortOrder'' ModelId
            "name" -> Just $    sortOrder'' ModelName
            "created" -> Just $ sortOrder'' ModelCreated
            _ -> Nothing
        where sortOrder' = case sortOrder of  
                    "Asc" -> Just Asc 
                    "Desc" -> Just Desc 
                    _ -> Nothing

我得到的错误是ModelIdModelName属于不同类型。这是因为sortOrder''是单独使用的吗?

2 个答案:

答案 0 :(得分:1)

我通过将查找键放在关联列表中来修改您的设计。将数据移动到数据结构而不是控制结构似乎是一种胜利。我也对你的类型(或与它们类似的类型)做了一些假设。根据您是否喜欢/ grok Applicatives:

,这里有两个选项
module Sorting where

import Control.Applicative ((<*>))

data Field = ModelId | ModelName | ModelCreated

data Sorting = Asc Field | Desc Field

orderMap :: [(String, Field -> Sorting)]
orderMap =
  [ ("Asc", Asc)
  , ("Desc", Desc)
  ]

fieldMap :: [(String, Field)]
fieldMap =
  [ ("id", ModelId)
  , ("name", ModelName)
  , ("created", ModelCreated)
  ]

lookupSorting :: String -> String -> Maybe Sorting
lookupSorting orderName fieldName = do
  order <- lookup orderName orderMap
  field <- lookup fieldName fieldMap
  return (order field)

lookupSorting' :: String -> String -> Maybe Sorting
lookupSorting' orderName fieldName =
  lookup orderName orderMap <*> lookup fieldName fieldMap

答案 1 :(得分:1)

尝试为sortOrder'提供类型签名。

where sortOrder' :: EntityField Model typ -> SelectOpt Model
      sortOrder' = case sortOrder of 
                    "Asc" -> Asc
                    "Desc" -> Desc

This compiles使用GHC 7.6.2。