Haskell 创建typeclass时,无法从上下文推断
我正在使用库,我想自动将结果映射到错误代码中。仆人需要类型:Haskell 创建typeclass时,无法从上下文推断,haskell,typeclass,Haskell,Typeclass,我正在使用库,我想自动将结果映射到错误代码中。仆人需要类型:或(Int,String)a 例如,如果我有一个类型为:IO(可能是User)的模型函数。我想把它转到(404,“未找到”)上,如果它在那里,则转到用户 为了做到这一点,我正在写一个typeclass class Servile a where toStatus :: ToJSON val => a -> Either (Int, String) val instance ToJSON a => Servil
或(Int,String)a
例如,如果我有一个类型为:IO(可能是User)
的模型函数。我想把它转到(404,“未找到”)
上,如果它在那里,则转到用户
为了做到这一点,我正在写一个typeclass
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
做这件事的正确方法是什么?我跳到哈斯克尔身上,因为我没有很好地表达这个问题。问题是,它不能在任何a
上变化,以生成这样的val
。这也证明了ToJSON
与这个问题无关
这是有效的:请注意,我将toStatus
更改为aval
,而不是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
类ToStatus a,其中
toStatus::a val->or(Int,String)val
比如托斯塔斯,可能在哪里
toStatus Nothing=左侧(404,“未找到”)
toStatus(仅v)=右v
实例Show a=>ToStatus(或a),其中
toStatus(左a)=左(500,“服务器错误:”显示a)
toStatus(右v)=右v
如果您想使用一些非参数化类型,另一种解决方案是使用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)
{-#语言类型族}
{-#语言灵活实例}
模块温度在哪里
导入数据.幺半群
托斯塔斯a班在哪里
Val a型
toStatus::a->other(Int,String)(Val a)
实例ToStatus(可能是a)在哪里
类型Val(可能是a)=a
toStatus Nothing=左侧(404,“未找到”)
toStatus(仅v)=右v
实例Show a=>ToStatus(a或b),其中
类型Val(a或b)=b
toStatus(左e)=左(500,“服务器错误:”显示e)
toStatus(右v)=右v
实例ToStatus字符串,其中
类型Val String=()
toStatus“200成功”=右()
toStatus err=左(500,err)
这不应该是toStatus::ToJSON a=>a->other(Int,String)a
?那么可能是toStatus::ToJSON a=>a->other(Int,String)JSON
?您希望如何将a
转换成任何ToJSON val=>val
?您当前的typeclass所说的是,您希望能够将一些实现了Servile
的a
转换为任何ToJSON
类型。您可以通过使用toStatus::a->任意一个(Int,String)值
来解决这个问题。直接返回值
s意味着您不必担心模棱两可。在Servile
实例中,您必须担心转换,但是如果您正在使用的已经实现了ToJSON
,那么转换就足够简单了。如果您正在使用的东西没有实现ToJSON
,那么您必须在您关心转换的地方处理它。完成后,您可以对所有内容调用toStatus
,而不必担心重叠实例、不一致实例等。保持简单,只返回具体类型。@seanclakhes您想从a
中提取ToJSON val=>val
,但是,a
没有限制这样说。val
类型变量仅出现在toStatus
的签名中,它当前必须来自任何地方。你能编辑你的问题来展示更多你想做的事情吗?哇,酷!有你推荐的类型系列介绍吗?@SeanClarkHess我很喜欢——也有