简体   繁体   English

Haskell-字符串函数

[英]Haskell - string function

I need to write function, which is seeking for "Z" in string, and when this function finds it on i index, it appends i+3 Char to table. 我需要编写函数,该函数在字符串中寻找“ Z”,并且当此函数在i索引上找到它时,它将i + 3 Char附加到表中。

Here is my code: 这是我的代码:

someFun :: String => String -> String -> String
someFun "" (r:rs) = (r:rs)
someFun (a:b:c:d:xs) (r:rs)
    | a == "Z" = someFun xs ((r:rs)++d)
    | otherwise = someFun (b:c:d:xs) (r:rs)

I got bunch of errors that I don't know how to fix due to my poor experience in Haskell programming. 由于我在Haskell编程方面的不良经验,我遇到了很多不知道如何解决的错误。

EDIT: If input is "(C (N (Z 'p')) (A (K (Z 'p') (Z 'q')) (Z 'r')))" its output should be: ['p','q','r'] 编辑:如果输入为“ [(C(N(Z'p'))(A(K(Z'p')(Z'q'))(Z'r'))))”,则其输出应为:[' p','q','r']

The specification is not entirely clear, but it sounds like you want to collect all the characters which occur three places after a 'Z' in the input, so that from 规范并不完全清楚,但是听起来您想收集输入中'Z'之后三位出现的所有字符,以便

"BUZZARD BAZOOKA ZOOM"

we get 我们得到

"RDKM"

Without a clearer presentation of the problem, it is difficult to give precise advice. 如果没有更清楚地表达问题,就很难给出准确的建议。 But I hope I can help you get past some of the small irritations, so that you can engage with the actual logic of the problem. 但我希望我能帮助您克服一些小麻烦,以便您可以解决问题的实际逻辑。

Let's start with the type. 让我们从类型开始。 You have 你有

someFun :: String => String -> String -> String

but left of => is the place for properties of type expressions, usually involving variables that could stand for lots of types, such as Eq a (meaning that whatever type a is, we can test equality). 但是=>左边是类型表达式的属性的位置,通常涉及可以代表许多类型的变量,例如Eq a (意味着无论a是什么类型,我们都可以测试相等性)。 String is a type, not a property, so it cannot stand left of => . String是一种类型,而不是属性,因此它不能位于=>左边。 Drop it. 算了吧。 That gives 那给

someFun  :: String -- input
         -> String -- accumulating the output (?)
         -> String -- output

It is not clear whether you really need an accumulator. 尚不清楚您是否真的需要累加器。 Suppose you know the output for 假设您知道输出

"ZARD BAZOOKA BOOM"  -- "DKM", right?

Can you compute the output for 你可以计算输出

"ZZARD BAZOOKA BOOM"  -- "RDKM"

? Just an extra 'R' on the front, right? 前面只是一个额外的'R' ,对吗? You're using tail recursion to do the next thing, when it is usually simpler to think about what things should be . 当通常更简单地考虑应该什么时,您将使用尾部递归来做下一件事。 If you know what the output is for the tail of the list, then say what the output is for the whole of the list. 如果你知道输出什么列表的尾部,然后说输出什么对整个名单。 Why not just map input to output directly, so 为什么不直接将输入映射为输出,所以

someFun :: String -> String

Now, pattern matching, start with the simplest possible pattern 现在,模式匹配从最简单的模式开始

someFun s = undefined

Can you see enough about the input to determine the output? 您是否对输入有足够的了解来确定输出? Clearly not. 显然不是。 It matters whether the input is empty or has a first character. 输入是否为空或具有第一个字符都很重要。 Split into two cases. 分为两种情况。

someFun ""      = undefined
someFun (c : s) = undefined   -- c is the first Char, s is the rest of the String

It also matters whether the first character is 'Z' or not. 第一个字符是否为'Z'也很重要。 Be careful to use single quotes for Char and double quotes for String : they are different types. 小心使用Char 引号和String 引号:它们是不同的类型。

someFun ""         = undefined
someFun ('Z' : s)  = undefined   -- the first Char is Z
someFun (c : s)    = undefined

In the case wit 'Z' , you also want to make sure that s has at least three characters, and we care about the third, so 'Z'的情况下,您还需要确保s至少包含三个字符,我们关心第三个字符,因此

someFun ""                         = undefined   -- input empty
someFun ('Z' : s@(_ : _ : d : _))  = undefined   -- first is 'Z' and d is 3 later
someFun (c : s)                    = undefined   -- input nonempty

The @ is an "as pattern", allowing me to name the whole tail s and also check that it matches (_ : _ : d : _) , grabbing the third character after the 'Z' . @是一个“作为模式”,允许我命名整个尾巴s ,并检查它是否匹配(_ : _ : d : _) ,抓住'Z'之后的第三个字符。

So far, I've given no thought to the output, just what I need to see about the input. 到目前为止,我还没有考虑到输出,只是我需要了解输入的内容。 Let's figure out what the output must be. 让我们弄清楚输出必须是什么。 In the first case, empty input gives empty output 在第一种情况下,空输入给出空输出

someFun ""                         = ""
someFun ('Z' : s@(_ : _ : d : _))  = undefined   -- first is 'Z' and d is 3 later
someFun (c : s)                    = undefined   -- input nonempty

and in the other two cases, we can assume that someFun s already tells us the output for the tail of the list, so we just need to figure out how to finish the output for the whole list. 在其他两种情况下,我们可以假设someFun s已经告诉我们列表尾部的输出,因此我们只需要弄清楚如何完成整个列表的输出即可。 In the last line, the output for the tail is just what we want. 在最后一行中,尾部的输出正是我们想要的。

someFun ""                         = ""
someFun ('Z' : s@(_ : _ : d : _))  = undefined   -- first is 'Z' and d is 3 later
someFun (c : s)                    = someFun s

But in the case where we've found that d is three places after the initial 'Z' , we need to make sure d is at the start of the output. 但是,如果我们发现d在初始'Z'之后三位,我们需要确保d在输出的开头。

someFun ""                         = ""
someFun ('Z' : s@(_ : _ : d : _))  = d : someFun s
someFun (c : s)                    = someFun s

Just checking: 只是检查:

*Main> someFun "BUZZARD BAZOOKA ZOOM"
"RDKM"

The key idea is to figure out how to express the output for the whole input in terms of the output for its pieces: what it is , not what to do . 关键思想是弄清楚如何用各个部分的输出来表示整个输入的输出: 它是什么,而不是做什么 Here, you can assume that the output for the tail, s is correctly computed, so you just need to figure out whether you have anything extra to return. 在这里,您可以假设尾部s的输出是正确计算的,因此您只需要弄清楚是否还有其他要返回的内容。

It's not really clear what you're trying to do but this compiles: 目前尚不清楚您要做什么,但这可以编译:

someFun :: String -> String -> String
someFun "" (r:rs) = (r:rs)
someFun (a:b:c:d:xs) (r:rs)
    | a == 'Z' = someFun xs ((r:rs)++[d])
    | otherwise = someFun (b:c:d:xs) (r:rs)

The String => is for typeclass constraints, which you don't need. String =>用于类型类约束,您不需要。 d is a Char while (++) is defined on lists (of Chars in this case). d是一个Char ,而(++)是(对列表定义Chars在这种情况下)。

Your function has incomplete pattern matches, so you could also define those, which will simplify the existing cases: 您的函数的模式匹配不完整,因此您也可以定义这些匹配,从而简化现有情况:

someFun :: String -> String -> String
someFun _ [] = error "Empty string"
someFun "" s = s
someFun ('Z':b:c:d:xs) s = someFun xs (s++[d])
someFun (_:b:c:d:xs) s = someFun (b:c:d:xs) s
someFun _ _ = error "String was not in the expected format"

To display it on the screen you can use putStrLn or print : 要在屏幕上显示它,可以使用putStrLnprint

displaySomeFun :: String -> String -> IO ()
displaySomeFun s1 s2 = putStrLn (someFun s1 s2)

Lee showed how you get it to compile. Lee展示了如何进行编译。 There are still some things to say about: You have to provide more pattern-cases, You get an error for example if you try to run someFun "" "" , or someFun "A" "ABCD" 还有一些事情要说:您必须提供更多的模式用例,例如,如果您尝试运行someFun "" ""someFun "A" "ABCD" ,则会出现错误。

First improvement: Change (r:rs) to rs , you never use r , so you can change it to a more general case (that will fix the error on someFun "" "" ). 第一个改进:将(r:rs)更改为rs ,您永远不会使用r ,因此您可以将其更改为更一般的情况(这将在someFun "" ""上修复错误)。 The other thing is, that you don't pattern match on lists with one, two, or tree elements. 另一件事是,您不对具有一个,两个或树元素的列表进行模式匹配。 You could add someFun _ rs = rs , so that in those cases nothing happens. 您可以添加someFun _ rs = rs ,这样在这些情况下就不会发生任何事情。

Read about head and tail.It is easier with them.And end the cycle when the length of your first list is less than 4. 阅读有关头和尾的信息,使用它们会更容易,并且当第一个列表的长度小于4时结束循环。

someFun [] rs = rs
someFun xs rs
| (length xs) < 4 = rs
| (head xs) == 'Z' = someFun (tail xs) (rs ++ [head (tail (tail (tail xs)))])
| otherwise = someFun (tail xs) rs

You can take advantage of how failing pattern-matches work in list comprehensions and the Data.List.tails function: 您可以在列表Data.List.tailsData.List.tails函数中利用失败的模式匹配的工作方式:

import Data.List (tails)

someFun :: String -> String
someFun s = [x | 'Z':_:_:x:_ <- tails s]

The tails function gives you all tails of a list (remember that a String ist just a list of Char ), eg: tails函数为您提供列表的所有尾部(记住String只是Char的列表),例如:

λ: tails "Overflow"
["Overflow","verflow","erflow","rflow","flow","low","ow","w",""]

The pattern ('Z':_:_:x:_) matches any string which starts with a Z and is at least four characters in size. 模式('Z':_:_:x:_)匹配以Z开头且大小至少为四个字符的任何字符串。 For each pattern match, the character which is three positions after Z is extracted. 对于每个模式匹配,提取Z之后三个位置的字符。

The magical part about it is that when the pattern fails (eg for tails which don't start with a Z or which are too short), the element is skipped silently and doesn't contribute to the result - exactly what you seem to request. 关于它的神奇之处在于,当模式失败时 (例如,对于不是以Z开头的尾巴或太短的尾巴),该元素将被静默跳过,并且不会对结果有所贡献-正是您所要求的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM