【问题标题】:Haskell - Number of occurencies of a Char in a String [duplicate]Haskell - 字符串中字符的出现次数[重复]
【发布时间】:2021-11-29 12:44:33
【问题描述】:

我正在 Haskell 中编写一个函数来计算字符串中 Char 值的出现次数,但在模式匹配时出现错误。有什么办法可以改变模式匹配来检查'xs'字符串的第一个值是否是'a'?

howMany :: Char -> String -> Int
howMany a [] = 0
howMany a (a : xs) = 1 + howMany a xs
howMany a (x : xs) = 0 + howMany a xs

【问题讨论】:

  • 顺便说一句,filter 已经实现了这里使用的递归模式。 howMany a = length . filter (== a)。不需要显式递归和模式匹配。

标签: haskell functional-programming pattern-matching


【解决方案1】:

所有模式都应该是线性的:这意味着你不能在函数的头部使用相同的变量两次。 Haskell 进行模式匹配,而不是像 Prolog 中的 unification。这是在section 3.17.1 Patterns of the Haskell report 中指定的:

所有模式都必须是线性的没有变量可能出现多次。例如,这个定义是非法的:

f (x,x) = x     -- ILLEGAL; x used twice in pattern 

因此,您应该在守卫的帮助下检查x == a

howMany :: Char -> String -> Int
howMany a [] = 0
howMany a (x : xs)
  | x == a = 1 + howMany a xs
  | otherwise = howMany a xs

【讨论】:

  • 谢谢!不使用守卫可以解决这个问题吗?
  • @PeterKiss:使用if-then-else,但基本相同。您需要使用== 来检查两个项目的等价性。您无法检查模式是否会统一。
  • @PéterKiss 是的,还有很多其他方式。有威廉建议的if-then-else;还有fromEnum :: Bool -> Int 和使用case x == a of ... 等等。最后,它们都归结为Bool 上的模式匹配,不过(即使是这里显示的守卫)。
【解决方案2】:

想一想,您的代码将如何转换为使用与case 的显式模式匹配?

howMany :: a -> [a] -> Int
howMany a b = case b of
    []       -> 0                   -- case 1
    (a : xs) -> 1 + howMany a xs    -- case 2
    (x : xs) -> 0 + howMany a xs    -- case 3

-- case 2 中的a 是一个全新的变量,完全独立于作为howMany 的形式参数的外部a。它可以用任何其他名称命名,例如

howMany :: a -> [a] -> Int
howMany a b = case b of
    []       -> 0                   -- case 1
    (x : xs) -> 1 + howMany a xs    -- case 2
    (x : xs) -> 0 + howMany a xs    -- case 3

现在我们也清楚地看到了之前的真实情况——案例 2 和案例 3 是一回事。

但这不是我们想要的。我们想区分x==a 的情况和它的否定。

解决方案就是明确我们的意图:

howMany :: Eq a => a -> [a] -> Int
howMany a b = case b of
    []       -> 0                   -- case 1
    (x : xs) 
      | x==a -> 1 + howMany a xs    -- case 2
    (x : xs) -> 0 + howMany a xs    -- case 3

上面可以用 lambda 表示法进一步翻译为

howMany :: Eq a => a -> [a] -> Int
howMany = \a -> (\b -> case b of
    []       -> 0                   -- case 1
    (x : xs) 
      | x==a -> 1 + howMany a xs    -- case 2
    (x : xs) -> 0 + howMany a xs )  -- case 3

这就是为什么在 Haskell 中不允许使用非线性模式的原因——因为函数的参数是一个一个的模式匹配,而不是一致的。

这就是另一个答案中的“匹配,不统一”技术评论的意思。 inner lambda 本身就是一个 Haskell 值,独立存在。但是,如果要区分其参数变量名称,则必须根据某个外部环境中的某个其他变量做出不同的行为——不,要不同?那是不行的。

【讨论】:

    猜你喜欢
    • 2012-05-10
    • 2012-05-31
    • 2011-03-02
    • 1970-01-01
    • 2021-01-11
    • 2017-06-16
    • 1970-01-01
    相关资源
    最近更新 更多