【问题标题】:Haskell read function overloading with two inputs具有两个输入的 Haskell 读取函数重载
【发布时间】:2017-03-18 20:01:25
【问题描述】:

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

我的问题是:是否可以通过重载 read 函数 来编写 reading 操作 并以这种方式使用它:read dbList "key1"?如果是,我该如何解决这个问题?输出需要为("not found","value data for key not exists")("found", "value1")

我已经查找了如何解决这个问题,但我发现的只是如何对一个输入参数使用读取函数以及如何定义新类型以便为该特定类型创建读取实例是需要的。但是我仍然很好奇我是否可以用两个输入参数以某种方式重载读取函数。

【问题讨论】:

  • read :: Read a => String -> a 用于从字符串表示创建特定类型的值,而不是用于执行数据库查找。
  • 感谢您的有用评论。我的老板要求我将 read 函数与预期的代码示例一起使用,我想确定这是否可行,因为我找不到任何解决方法。
  • 他知道Read 类吗? read 本身不能被重载,因为它实际上不是由 Read 类定义的。
  • 也许他只是写了一个例子,也许他没有深入分析。我认为如果不是逐个字符读取 就可以了。我只是好奇在行动之前是否有可能。

标签: haskell overloading


【解决方案1】:

你想要的函数是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")

【讨论】:

    【解决方案2】:

    为了完整起见,我将介绍一种使用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, "")]
    

    这里我们为DB -> (String, String) 类型定义了一个Read 的实例。回想一下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, "")],其中f 是一个DB -> (String, String) 类型的函数,它在其参数db 中执行keylookup

    现在我们可以像这样使用这个实例了:

    > read "foo" [("foo", "bar")] :: (String, String)
    ("found","bar")
    
    > read "baz" [("foo", "bar")] :: (String, String)
    ("not found","data for baz does not exist")
    

    我再次强调,这是一个不寻常的实例,可能会在实际代码中引起混淆——您应该直接使用lookup

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      • 2015-02-13
      相关资源
      最近更新 更多