我已经在这个问题上挣扎了一两个小时,我发现很难将心理概念转化为实际的代码。感觉我错过了一些与类型相关的知识 - 但我不确定是什么。
基本上我们有以下代码:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
module Routes where
data RouteUrl a = Dashboard
| CreatePost
| ListPost
| EditPost a
| DeletePost a
| Register
| Login deriving Show
data PublicUrl = PublicUrl (RouteUrl Int)
data PlaceHolderUrl = PlaceHolderUrl (RouteUrl String)
data UrlSum = UrlPub PublicUrl | UrlPla PlaceHolderUrl
getUrl :: UrlSum -> String
getUrl (UrlPub (PublicUrl (Dashboard))) = "/dashboard"
getUrl (UrlPla (PlaceHolderUrl (Dashboard))) = "/dashboard"
getUrl (UrlPub (PublicUrl (EditPost x))) = "/editpost/" ++ show x
getUrl (UrlPla (PlaceHolderUrl (EditPost x))) = "/editpost/(abcxyz)" ++ show x
以上工作正常,但我试图找到一种方法来避免重复"/dashboard"
,"/editpost/..."
部分。
输出的唯一区别应该是PlaceHolderUrl
我们应该在参数前加上(abcxyz)
。
因此,在我的心智模型中,我只是在思考"查看外部类型(PublicUrl或PlaceHolderUrl),并使用为该类型分配的适当函数" 我以为我可以按照以下方式做点什么:
getUrl' :: (RenderUrlComponent u b) Int => u -> String
getUrl' u = case (getRouteUrl u) of
Dashboard -> "/dashboard"
(EditPost x) -> "/editpost/" ++ renderUrlComponent u
class RenderUrlComponent a b where
renderUrlComponent :: a -> String
getRoute :: a -> RouteUrl b
instance RenderUrlComponent PublicUrl Int where
renderUrlComponent publicUrl = getRoute publicUrl :: RouteUrl Int
getRoute (PublicUrl x) = x
但是除了上述内容之外还有以下错误:
• Expecting one fewer arguments to ‘RenderUrlComponent u b’ Expected kind ‘* -> Constraint’, but ‘RenderUrlComponent u b’ has kind ‘Constraint’ • In the type signature: getUrl' :: (RenderUrlComponent u b) Int => u -> String | 26 |
我无法弄清楚如何从getRoute publicUrl :: RouteUrl Int
中获取Int,而不必采用模式匹配,在这种情况下,我回过头来解决我遇到的问题。< / p>
我似乎正在寻找以下内容:
x是y的实例,如果它包含在z中。
答案 0 :(得分:4)
只需创建一个帮助函数来抽象出通用性,不需要(或证明)这里的类。
module Routes where
data RouteUrl a = Dashboard
| CreatePost
| ListPost
| EditPost a
| DeletePost a
| Register
| Login deriving Show
data PublicUrl = PublicUrl (RouteUrl Int)
data PlaceHolderUrl = PlaceHolderUrl (RouteUrl String)
data UrlSum = UrlPub PublicUrl | UrlPla PlaceHolderUrl
getUrlRU :: (Show a) => (String -> String) -> RouteUrl a -> String
getUrlRU prefix ru =
case ru of
Dashboard -> "/dashboard"
EditPost x -> "/editpost/" ++ prefix (show x)
....
getUrl :: UrlSum -> String
getUrl (UrlPub (PublicUrl x)) = getUrlRU id x
getUrl (UrlPla (PlaceHodlerUrl x)) = getUrlRU ("(abcxyz)" ++) x
如果您不想要,则不必传递函数,您可以将字符串作为字符串prefix ++ (show x)
。传递一个函数会给你一些灵活性,如果你以某种方式过度简化你的问题可能会有所帮助。
答案 1 :(得分:0)
RouteUrl
传递给参数修饰符函数f
虽然被忽略,但编译器可以推断出要使用的实例...
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# OPTIONs -Wno-incomplete-patterns #-}
module Routes where
data RouteUrl a b = Dashboard
| CreatePost
| ListPost
| EditPost a
| DeletePost a
| Register
| Login deriving Show
data PublicUrl
data PlaceHolderUrl
data NormalizedUrl
class Show a => RouteParam a b where
f :: RouteUrl a b -> String -> String
normalParam :: RouteUrl a b -> RouteUrl String NormalizedUrl
normalParam (Dashboard) = Dashboard
normalParam (CreatePost) = CreatePost
normalParam (ListPost) = ListPost
normalParam (EditPost x ) = EditPost $ show x
normalParam (DeletePost x ) = DeletePost $ show x
normalParam (Register) = Register
normalParam (Login) = Login
instance RouteParam Int PublicUrl where
f _ = id
instance RouteParam String PlaceHolderUrl where
f _ = ("(abcxyz)" ++)
renderUrl :: RouteParam a b => RouteUrl a b -> String
renderUrl r = case normalParam r of
Dashboard -> "/dashboard/"
EditPost x -> "/editpost/" ++ (f r x)
renderPublicUrl:: RouteUrl Int PublicUrl -> String
renderPublicUrl r = renderUrl r
renderPlaceHolderUrl :: RouteUrl String PlaceHolderUrl -> String
renderPlaceHolderUrl r = renderUrl r