我正在使用Servant库,我想自动将结果映射到错误代码中。 Servant期望类型:Either (Int, String) a
。
例如,如果我有一个类型为IO (Maybe User)
的模型函数。我想把它转到(404, "Not Found")
上没有,而User
如果它在那里。
要做到这一点,我正在编写一个类型类!
class Servile a where
toStatus :: ToJSON val => a -> Either (Int, String) val
instance ToJSON a => Servile (Maybe a) where
toStatus Nothing = Left (404, "Not Found")
toStatus (Just a) = Right a
我还有其他想写的实例,但这个实例给了我错误:
Could not deduce (a ~ val)
from the context (ToJSON a)
bound by the instance declaration at Serials/Api.hs:90:10-38
or from (ToJSON val)
bound by the type signature for
toStatus :: ToJSON val => Maybe a -> Either (Int, String) val
at Serials/Api.hs:91:5-12
‘a’ is a rigid type variable bound by
the instance declaration at Serials/Api.hs:90:10
‘val’ is a rigid type variable bound by
the type signature for
toStatus :: ToJSON val => Maybe a -> Either (Int, String) val
at Serials/Api.hs:91:5
Relevant bindings include
a :: a (bound at Serials/Api.hs:92:20)
toStatus :: Maybe a -> Either (Int, String) val
(bound at Serials/Api.hs:91:5)
In the first argument of ‘Right’, namely ‘a’
In the expression: Right a
这样做的正确方法是什么?
答案 0 :(得分:4)
如果您想使用某些非参数化类型,另一种解决方案是使用TypeFamilies
:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
module Temp where
import Data.Monoid
class ToStatus a where
type Val a
toStatus :: a -> Either (Int, String) (Val a)
instance ToStatus (Maybe a) where
type Val (Maybe a) = a
toStatus Nothing = Left (404, "Not Found")
toStatus (Just v) = Right v
instance Show a => ToStatus (Either a b) where
type Val (Either a b) = b
toStatus (Left e) = Left (500, "Server Error: " <> show e)
toStatus (Right v) = Right v
instance ToStatus String where
type Val String = ()
toStatus "200 Success" = Right ()
toStatus err = Left (500, err)
答案 1 :(得分:3)
我跳过#haskell,因为我没有很好地表达这个问题。问题是,它不能在任何a
之间变化,以产生类似的val
。事实证明ToJSON
与此问题无关。
这有效:请注意,我将toStatus
更改为a val
而不是a
,以及删除类型变量的实例。
class ToStatus a where
toStatus :: a val -> Either (Int, String) val
instance ToStatus Maybe where
toStatus Nothing = Left (404, "Not Found")
toStatus (Just v) = Right v
instance Show a => ToStatus (Either a) where
toStatus (Left a) = Left (500, "Server Error: " <> show a)
toStatus (Right v) = Right v