在我的haskell程序中,我有一个代表[(key, value)]
格式的数据库的列表。例如,这是一个有效的数据库:[("key1", "value1"), ("key2", "value2"), ("key3", "value3")]
。 键和值数据将始终具有 String 类型。
我的问题是:是否可以通过重载读取功能来编码阅读操作并以这种方式使用它:read dbList "key1"
?如果是,我该如何解决这个问题?输出必须为("not found","value data for key not exists")
或("found", "value1")
。
我已经查询了如何解决这个问题,但我发现的所有内容都是如何将read函数用于一个输入参数以及如何定义一个新类型,以便为该特定类型创建一个读取实例需要。但我仍然很好奇,如果我可以用两个输入参数以某种方式重载读取函数。
答案 0 :(得分:4)
您想要的功能是lookup
,它是Prelude的一部分。
> :t lookup
lookup :: Eq a => a -> [(a, b)] -> Maybe b
> let dbList = [("key1", "value1")]
> lookup "key1" dbList
Just "value1"
> lookup "key2" dbList
Nothing
如果您确实需要显示的元组表单中的输出,则可以对结果进行模式匹配。
case lookup dbList someKey of
Just x -> ("found", x)
Nothing -> ("not found", "data for " ++ key ++ " does not exist")
答案 1 :(得分:3)
为了完整起见,我将介绍一种使用read
进行操作的方法。但是,这是非常不寻常的,我认为这是一个坏主意,因为你可以使用lookup
。
{-# LANGUAGE FlexibleContexts, FlexibleInstances #-}
type DB = [(String, String)]
instance Read (DB -> (String, String)) where
readsPrec _ = \key -> let
f db = case lookup key db of
Just x -> ("found", x)
Nothing -> ("not found", "data for " ++ key ++ " does not exist")
in [(f, "")]
这里我们为类型Read
定义DB -> (String, String)
的实例。回想一下,read
函数的类型为Read a => String -> a
,因此此实例为我们提供了read
类型为String -> DB -> (String, String)
的重载。
我们的实例定义readsPrec
函数,其类型为Read a => Int => ReadS a
,其中ReadS a
是String -> [(a, String)]
的别名。因此,我们的readsPrec
实施必须包含Int -> String -> [(DB -> (String, String), String)]
类型。我们不关心“优先级”参数,因此我们用_
忽略它。我们只关心在此实例中返回单个结果,因此我们只返回[(f, "")]
,其中f
是DB -> (String, String)
类型的函数,执行lookup
key
1}}在其参数db
。
现在我们可以像这样使用这个实例:
> read "foo" [("foo", "bar")] :: (String, String)
("found","bar")
> read "baz" [("foo", "bar")] :: (String, String)
("not found","data for baz does not exist")
我再次强调,这是一个不寻常的实例,可能会导致实际代码混淆 - 您应该直接使用lookup
。