Question

Is there a more elegant way of writing this: (the code below compiles)

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

The main problem is that I can't use a variable instead of the "Asc/Desc" case. Something like the code below, fails to typecheck.

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 says that it doesn't expect ModelId and ModelName to be a part of the same case since they're different types. Which I think is valid. However, Asc ModelId is the same type as Asc ModelName. How do I tell GHC that?


Hammar's initial answer works. This version still doesn't work:

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

I get the same error that ModelId and ModelName are of different types. Is this because sortOrder'' is being used monadically?

Was it helpful?

Solution

Try giving sortOrder' a type signature.

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

This compiles using GHC 7.6.2.

OTHER TIPS

I've modified your design a bit by putting the lookup keys in an association list. Moving data into data structures rather than control structures seems like a win. I'm also making some assumptions about your types (or types similar to them). Here are two options depending on whether or not you like/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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top