【问题标题】:Compare the head of a haskell string?比较haskell字符串的头部?
【发布时间】:2012-12-17 00:01:05
【问题描述】:

努力学习Haskell,如何获取字符串的头部并将其与下一个字符进行比较,直到找到一个注释为真的字符?

在伪代码中我正在尝试:

while x == 'next char in string' 放入要返回的新列表

【问题讨论】:

  • +1 请求指导而非解决方案
  • 我认为您正试图在字符串的开头找到重复的字符,这是正确的吗?您介意重新表述您的问题吗?
  • 这可能不是您想要的,但您可以从了解takeWhile and dropWhile 中受益

标签: haskell


【解决方案1】:

一般的方法是创建一个函数,递归地计算字符串的头部,直到找到错误值或到达结尾。

要做到这一点,你需要

  • 了解递归(先决条件:了解递归)以及如何在 Haskell 中编写递归函数
  • 知道如何使用head函数
  • 很可能知道如何在 Haskell 中使用列表推导

我有notes on Haskell,您可能会觉得它有用,但您可能会发现Yet Another Haskell Tutorial 更全面(3.3 列表3.5 函数;和 7.8 更多列表 可能是解决我提到的要点的好起点)

EDIT0: 使用守卫测试头元素并仅在它与第二个元素相同时继续的示例:

someFun :: String -> String 
someFun[] = [] 
someFun [x:y:xs]
    | x == y = someFun(y:xs)
    | otherwise = []

EDIT1:

我有点想说 x = (newlist) 然后而不是 else = [] 有 else = [newlist] 如果这有意义吗? 它在命令式编程范式(例如 C 或 Java)中是有意义的,而对于函数式方法则不那么有意义

这是一个具体的例子,希望能突出引用所暗示的 if,then,else 概念与 SomeFun 函数中发生的情况之间的区别:

当我们调用SomeFun [a,a,b,b] 时,我们将其与SomeFun [x:y:xs] 匹配,因为x 是'a',y 是'a',x==y,然后SomeFun [a,a,b,b] = SomeFun [a,b,b],它再次匹配@987654331 @ 但条件 x==y 为假,所以我们使用 else 守卫,所以我们得到 SomeFun [a,a,b,b] = SomeFun [a,b,b] = []。因此,SomeFun [a,a,b,b] 的结果是[]

那么数据去哪儿了? .好吧,我会举手承认代码中的一个错误,现在我用它来解释 Haskell 函数的工作原理。

我发现更多地从构造数学表达式而不是编程操作的角度思考是有帮助的。因此,= 右侧的表达式您的结果,不是命令式的赋值(例如 Java 或 C 意义上的)。

我希望具体的例子已经表明 Haskell 使用替换来评估表达式,所以如果你不想在结果中包含某些东西,那么不要将它包含在那个表达式中。相反,如果您确实想要结果中的某些内容,则将其放入表达式中。

因为你的伪代码是

while x == 'next char in string' 放入要返回的新列表

我将修改 SomeFun 函数来做相反的事情,让你弄清楚需要如何修改它才能按你的意愿工作。

someFun2 :: String -> String 
someFun2[] = [] 
someFun2 [x:y:xs]
    | x == y = []
    | otherwise = x : someFun(y:xs)

示例输出:

  • SomeFun2 [a,a,b,b] = []
  • SomeFun2 [a,b,b,a,b] = [a]
  • SomeFun2 [a,b,a,b,b,a,b] = [a,b,a]
  • SomeFun2 [a,b,a,b] = [a,b,a,b]

(此时我想补充一点,这些不同的代码 sn-ps 没有经过测试,因为我手头没有编译器,所以请指出任何错误,以便我修复它们,谢谢)

【讨论】:

  • 我了解递归以及如何使用 head 函数。我没有得到也找不到任何好的文档是如何根据语法等定义函数。例如: someFun :: String -> String someFun[] = [] someFun (x:xs) =我似乎无法获得正确的语法将头部分配给另一个列表,然后将其与下一个字符进行比较。我有一点感觉,如果我能完成我的第一个功能,那么一旦我有了工作的基础,剩下的工作就会容易得多。抱歉,回复太长了!
  • 我希望我没有给出太完整的答案,但我在你的评论中截取了片段,并尽我所能在我生锈的 Haskell 中完成了它。我认为这应该是一个很好的开始。
  • 这很有帮助。我见过其他人以另一种方式做到这一点,但它看起来有点啰嗦,我们被告知保护函数是最好的。要在字符串中使用 == 是否需要在类型中声明其他内容,而不仅仅是 String -> String?
  • 别在意最后一个,只是我很傻。我已经让它放弃了第一轮角色,所以只需进行一些调整以返回丢弃的角色而不是剩下的,我应该希望能够在我的第一个 haskell 中取得成功,这将是很棒的。谢谢。
  • 仍然有点卡住 Chirs,但它变得更清晰了。主要问题是我一直试图把它想象成其他语言,如 C 或 Java,这没有帮助。您在那里编写的程序 sn-p ,如果 x(头部)和 y(头部之后的字符)相等,则函数会重复。现在我如何将 x 放入一个新列表中以便稍后返回。我有点想说 x = (newlist) 然后而不是 else = [] 有 else = [newlist] 如果这有意义吗?
【解决方案2】:

有两种典型的方法来获取字符串的头部。 head,以及模式匹配(x:xs)

其实the source for the head functionshows只是用模式匹配定义的:

head (x:_) = x
head _     = badHead

我强烈建议您查看Learn You a Haskell # Pattern Matching。它给出了这个例子,这可能会有所帮助:

tell (x:y:[]) = "The list has two elements: " ++ show x ++ " and " ++ show y

注意它是如何与(x:y:[]) 匹配的,这意味着列表必须有两个元素,不能再多了。要匹配较长列表中的前两个元素,只需将 [] 替换为变量 (x:y:xs)

如果选择模式匹配方式,则需要使用递归。


另一种方法是zip xs (drop 1 xs)。这个小习语从列表中的相邻对创建元组。

ghci> let xs = [1,2,3,4,5]
ghci> zip xs (drop 1 xs)
[(1,2),(2,3),(3,4),(4,5)]

然后您可以编写一个函数来逐一查看这些元组。它也是递归的,但可以写成foldlfoldr


为了理解 Haskell 中的递归,再次强烈推荐 LYAH:

Learn You a Haskell # Recursion

【讨论】:

  • 谢谢你,我一直在阅读学习你的haskell,但我不明白的是类型。 (Show a) => [a] -> String 我以为类型只是 String -> String?
  • tell 使用 show 函数,它将实现 Show 的任何类型的值转换为字符串。因此列表不需要是字符列表(字符串),它可以是使用 show 有效的任何内容。这就是为什么类型签名是 (Show a) => [a] -> String
猜你喜欢
  • 1970-01-01
  • 2018-03-01
  • 1970-01-01
  • 2021-12-28
  • 2023-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多