【问题标题】:how could i return multiple values from a function in haskell?如何从haskell中的函数返回多个值?
【发布时间】:2014-09-22 11:08:21
【问题描述】:

一个函数是否可以返回多个值——例如,一个字符串和一个布尔值?

如果是,那么我有一个名为 concat 的函数,它返回一个 Bool 和一个 String,但我不知道如何调用该函数以便我可以存储结果。

示例尝试:

concat::(String->Int)->(IO Bool->IO String)
concat line i=do
       return True line

你能帮我写一下函数签名以及如何调用这些函数吗?

【问题讨论】:

    标签: haskell types tuples


    【解决方案1】:

    返回多个值时,您必须返回代数数据类型。这个可以说很多,我给你一些建议。

    1. 如果您的 BoolString 在某种程度上更相关,并且它们经常在您的代码中一起出现,请定义一个新的代数数据类型:

      data Question = Question Bool String
      

      您也可以使用访问器函数来定义它,它也记录数据:

      data Question = Question{ answered :: Bool
                              , text     :: String }
      

      你可以定义一个函数e。 G。初始化问题:

      question :: String -> Question
      question str = Question False (str ++ "?")
      

      或(用于改进文档):

      question :: String -> Question
      question str = Question{ answered = False
                             , text     = str ++ "?"}
      

      然后您可以使用数据构造函数处理您的数据:

      answer :: String -> Question -> Question
      answer answ (Question False str) =
        Question True (str ++ " " ++ answ ++ ".")
      answer _ old = old
      

      或使用访问器函数(这两种方法的许多组合都是可能的):

      answer :: String -> Question -> Question
      answer answ qstn
        | answered qstn = qstn
        | otherwise     = qstn{ answered = True
                              , text     = text qstn ++ " " ++ answ ++ "."}
      

      函数调用示例:

      answer "Yes it is" (question "Is this answer already too long")
      
    2. 如果您不想定义新的数据类型,请使用预定义的元组。标准库中定义了许多函数,使您更轻松地使用元组。但是,不要到处使用元组——更大的代码会变得一团糟(缺乏文档——不清楚元组代表什么数据),由于多态性,类型错误不会那么容易追踪。

      元组的一种方便使用的例子:

      squareAndCube :: Int -> (Int, Int)
      squareAndCube x = (square, square*x)
        where square = x*x
      
      sumOfSquareAndCube :: Int -> Int
      sumOfSquareAndCube x = square + cube
        where (square, cube) = squareAndCube x
      

      关于这个简单的问题说了太多,但由于我提到标准库支持是元组的主要优势,我将给出最后一个使用 Prelude 中的uncurry 函数的示例:

      sumOfSquareAndCube :: Int -> Int
      sumOfSquareAndCube x = uncurry (+) (squareAndCube x)
      

    【讨论】:

      【解决方案2】:

      是的,您可以使用称为元组的 haskell 构造返回多个值。

      这是一个简单的例子

      addAndSub :: Int -> Int -> (Int, Int)
      addAndSub a b = (a + b, a - b)
      

      然后您可以使用fst 访问元组的第一部分,使用snd 访问第二部分。但是最好是模式匹配

      use = case addAndSub 2 3 of
        (i, j) -> i + j
      

      let (i,j) = addAndSub 2 3 
      in i + j
      

      现在假设你的函数做了一些 IO 并得到一个String 和一个Bool,那么你的函数看起来就有点像

      magic :: IO (String, Bool)
      magic = do
        string <- getString
        bool   <- getBool
        return (string, bool)
      

      如果您正在使用 do 块在 monad 中工作,您还可以使用更漂亮的表单进行模式匹配。

      foo = do
       (i, j) <- magic
      

      注意这个必须在一个do块中。如果您要返回类型为 m a 的值,其中 m 是 monad,则只能使用 do 块,例如 IO

      【讨论】:

      • 我不想用这种情况可以这样写吗
      • @rahul 写哪个?
      • @rahul 我已经更新了。不要说你不能在任何地方使用 do 块,只有在做类似IO 的事情时。为什么不喜欢case 表单?
      • 我需要实现递归来找到路径这就是我不想用例的原因
      • @rahul 我贴的第二个表格其实只是一个加糖的案例,所以你可以使用任何一个。
      猜你喜欢
      • 2021-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-01
      相关资源
      最近更新 更多