【问题标题】:Types and higher-order function in HaskellHaskell 中的类型和高阶函数
【发布时间】:2021-08-11 13:41:57
【问题描述】:

谁能帮我理解这个问题。

我有这个简单的功能:

takeAsLong :: [a] -> (a -> Bool) -> [a]
takeAsLong [] _ = []
takeAsLong (x:xs) test | test x    = x : takeAsLong xs test
                       | otherwise = []

但是当我尝试使用 if-then-else 重写它时,我遇到了错误。

takeAsLong :: [a] -> (a -> Bool) -> [a]
takeAsLong [] _ = []
takeAsLong (x:xs) test = if test x then x : takeAsLong [xs] test else []

错误在“takeAsLong [xs] test”的递归调用中,但我不明白为什么它不喜欢它?

错误信息:

无法将类型“a”与“[a]”匹配 预期:[a] -> Bool 实际:a -> Bool ‘a’ 是一个刚性类型变量,由 类型签名: takeAsLong::forall 一个。 [a] -> (a -> Bool) -> [a]

那么为什么它期望函数测试是[a] -> Bool 以及为什么带有保护的版本没有同样的问题?

【问题讨论】:

    标签: haskell


    【解决方案1】:

    xs 是一个 list 项,除了第一项。如果您使用[xs],那么您将该列表包装在一个单例列表中。

    因此您应该调用takeAsLong xs test 而不是takeAsLong [xs] test

    takeAsLong :: [a] -> (a -> Bool) -> [a]
    takeAsLong [] _ = []
    takeAsLong (x:xs) test = if test x then x : takeAsLong xs test else []

    使用if-then-else 并不常见。通常谓词也将是第一个参数。所以可能会有一个更“Haskell-ish”的版本:

    takeAsLong :: (a -> Bool) -> [a] -> [a]
    takeAsLong p = go
        where go [] = []
              go (x:xs)
                  | p x = x : go xs
                  | otherwise = []

    这个函数已经存在并且被称为takeWhile :: (a -> Bool) -> [a] -> [a]

    【讨论】:

    • 这是我的一个愚蠢的错误。和错误消息。现在实际上有意义。谢谢。
    • @Andrej 别担心。学习 Haskell 的一个重要部分是学习理解 GHC 类型的错误消息。它们的信息量很大,但要弄清楚它们的含义需要一段时间。
    【解决方案2】:

    这里的主要问题是takeAsLong [xs] 部分,当你这样做时,你给函数takeAsLong :: [a] -> (a -> Bool) -> [a] 一个列表列表,takeAsLong :: [[a]] -> (a -> Bool) -> [a] 那个类型是可行的,但你键入的是另一个. @willem 回答中有如何做到这一点:

    takeAsLong :: [a] -> (a -> Bool) -> [a]
    takeAsLong [] _ = []
    takeAsLong (x:xs) test = if test x then x : takeAsLong xs test else []
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-21
      • 1970-01-01
      • 2011-12-13
      • 1970-01-01
      • 2023-03-12
      相关资源
      最近更新 更多