Haskell数据,自定义字符串值
我正在写一篇文章,我的一切都正常,但是我想在我的搜索过滤器(url参数)中引入更强的类型 示例调用如下所示:Haskell数据,自定义字符串值,haskell,sdk,http-conduit,Haskell,Sdk,Http Conduit,我正在写一篇文章,我的一切都正常,但是我想在我的搜索过滤器(url参数)中引入更强的类型 示例调用如下所示: -- list first 3 positive comments mentioned by females comments "tide-pods" [("limit", "3"),("sentiment", "positive"),("gender", "female")] config 虽然这对我来说不是太可怕,但我真的希望能够通过以下考试: comments "tide-pod
-- list first 3 positive comments mentioned by females
comments "tide-pods" [("limit", "3"),("sentiment", "positive"),("gender", "female")] config
虽然这对我来说不是太可怕,但我真的希望能够通过以下考试:
comments "tide-pods" [("limit", "3"),(Sentiment, Positive),(Gender, Male)] config
或者类似的东西
在DataRank.hs中,您可以看到我的url参数类型type QueryParameter=(String,String)
,以及转换http管道参数的代码convertParameters::[QueryParameter]->[(ByteString,可能ByteString)]
我一直在试验数据/类型,例如:
data Gender = Male | Female | Any
-- desired values of above data types
-- Male = "male"
-- Female = "female"
-- Any = "male,female"
api还需要对任意字符串键、字符串值保持足够的灵活性,因为我希望SDK能够在不依赖SDK更新的情况下提供新过滤器。对于好奇的人来说,最新构建的搜索过滤器列表中有一个到目前为止的搜索过滤器列表
我在Haskell中找到一个提供搜索界面的好方法时遇到了问题。提前谢谢 保持其简单但不安全的最简单方法是只使用带有
任意
字段的基本ADT,该字段接受字符串
键和值:
data FilterKey
= Arbitrary String String
| Sentiment Sentiment
| Gender Gender
deriving (Eq, Show)
data Sentiment
= Positive
| Negative
| Neutral
deriving (Eq, Show, Bounded, Enum)
data Gender
= Male
| Female
| Any
deriving (Eq, Show, Bounded, Enum)
然后您需要一个函数来将FilterKey
转换为API的基本(字符串,字符串)
过滤器类型
filterKeyToPair :: FilterKey -> (String, String)
filterKeyToPair (Arbitrary key val) = (key, val)
filterKeyToPair (Sentiment sentiment) = ("sentiment", showSentiment sentiment)
filterKeyToPair (Gender gender) = ("gender", showGender gender)
showSentiment :: Sentiment -> String
showSentiment s = case s of
Positive -> "positive"
Negative -> "negative"
Neutral -> "neutral"
showGender :: Gender -> String
showGender g = case g of
Male -> "male"
Female -> "female"
Any -> "male,female"
最后,您只需包装基本API的注释
函数,这样filters参数的类型就更安全了,并在内部转换为(String,String)
表单来发送请求
comments :: String -> [FilterKey] -> Config -> Result
comments name filters conf = do
let filterPairs = map filterKeyToPair filters
commentsRaw name filterPairs conf
这将非常有效,并且非常容易使用:
comments "tide-pods" [Arbitrary "limits" "3", Sentiment Positive, Gender Female] config
但它的可扩展性不强。如果您库的用户希望扩展它以添加limitint
字段,则必须将其编写为
data Limit = Limit Int
limitToFilterKey :: Limit -> FilterKey
limitToFilterKey (Limit l) = Arbitrary "limit" (show l)
相反,它看起来像
[limitToFilterKey (Limit 3), Sentiment Positive, Gender Female]
这并不特别好,尤其是当他们试图添加许多不同的字段和类型时。一个复杂但可扩展的解决方案是使用单个过滤器
类型,实际上为了简单起见,让它能够表示单个过滤器或过滤器列表(尝试在Filter=Filter[(String,String)]
的地方实现它,干净地实现它有点困难):
然后有一个类来表示到过滤器的转换(很像Data.Aeson.ToJSON
):
Filter
的例子非常简单
instance FilterKey Filter where
-- Unsafe because it doesn't match the Fitlers contructor
-- but I never said this was a fully fleshed out API
keyToString (Filter (k, _)) = k
valToString (Filter (_, v)) = v
toFilter = id
在这里,您可以轻松组合这种类型的值的一个快速技巧是
-- Same fixity as <>
infixr 6 &
(&) :: (FilterKey kv1, FilterKey kv2) => kv1 -> kv2 -> Filter
kv1 & kv2 = toFilter kv1 <> toFilter kv2
加一点糖:
data Is = Is
is :: Is
is = Is
sentiment :: Is -> Sentiment -> Sentiment
sentiment _ = id
gender :: Is -> Gender -> Gender
gender _ = id
您可以编写如下查询
example
= comments "tide-pods" config
$ "limit" .= "3"
& sentiment is Positive
& gender is Any
如果不将构造函数导出到Filter
,并且不将toFilter
导出,则此API仍然是安全的。我把它作为一个方法留在typeclass上,这样Filter
就可以用id
覆盖它,从而提高效率。然后,您的库的用户只需执行以下操作
data Limit
= Limit Int
deriving (Eq, Show)
instance FilterKey Limit where
keyToString _ = "limit"
valToString (Limit l) = show l
如果他们想保持is
风格,他们可以使用
limit :: Is -> Int -> Limit
limit _ = Limit
写一些类似的东西
example
= comments "foo" config
$ limit is 3
& sentiment is Positive
& gender is Female
但这只是一个例子,可以让Haskell中的EDSL看起来非常可读。data FilterKey=touction-mountain-mountain-value | Gender-GenderValue |任意字符串
,然后你可以做注释“潮汐吊舱”[任意“限制”“3”,情绪积极,性别男性]config
你可以有一个comments::String->[FilterKey]->config->Result
和commentsRaw::String->[(String,String)]->config->Result,其中comments
调用commentsRaw
,只需编写一个函数filterKeyToPair::FilterKey->(String,String)
。那很简单,谢谢!现在,当我迭代要传递给http导管的参数列表时,如何获得所需的值(尤其是ANY=“male,female”?我是否只需执行保护并返回正确的字符串?如果您现在想保持简单,可以执行类似的操作。我通过为每个端点的选项创建数据类型来解决此问题。然后,我使用镜头干净地设置了特定选项。请查看我的库中的示例:。
data Limit
= Limit Int
deriving (Eq, Show)
instance FilterKey Limit where
keyToString _ = "limit"
valToString (Limit l) = show l
limit :: Is -> Int -> Limit
limit _ = Limit
example
= comments "foo" config
$ limit is 3
& sentiment is Positive
& gender is Female