Haskell使用两个输入读取函数重载

时间:2017-03-18 20:01:25

标签: haskell overloading

在我的haskell程序中,我有一个代表[(key, value)]格式的数据库的列表。例如,这是一个有效的数据库:[("key1", "value1"), ("key2", "value2"), ("key3", "value3")]数据将始终具有 String 类型。

我的问题是:是否可以通过重载读取功能来编码阅读操作并以这种方式使用它:read dbList "key1"?如果是,我该如何解决这个问题?输出必须为("not found","value data for key not exists")("found", "value1")

我已经查询了如何解决这个问题,但我发现的所有内容都是如何将read函数用于一个输入参数以及如何定义一个新类型,以便为该特定类型创建一个读取实例需要。但我仍然很好奇,如果我可以用两个输入参数以某种方式重载读取函数。

2 个答案:

答案 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 aString -> [(a, String)]的别名。因此,我们的readsPrec实施必须包含Int -> String -> [(DB -> (String, String), String)]类型。我们不关心“优先级”参数,因此我们用_忽略它。我们只关心在此实例中返回单个结果,因此我们只返回[(f, "")],其中fDB -> (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