开发者

is there a way for keeping a variable from changing inside recursions, in haskell?

开发者 https://www.devze.com 2022-12-16 17:52 出处:网络
i\'m trying to define the isInfixOf function, and i came to a solution(hope it works good :-)), but because of the recursion nature of haskell, i wrote another (help) function that

i'm trying to define the isInfixOf function, and i came to a solution(hope it works good :-)),

but because of the recursion nature of haskell, i wrote another (help) function that

almost duplicate the code of the function isInfixOf.

this is the code:

myIsInfixOf :: (Eq a) => [a] -> [a] -> Bool myIsInfixOf [] [] = True myIsInfixOf [] list = True myIsInfixOf list [] = False myIsInfixOf listA listB | helpFunction listA listB == True = True | otherwise = myIsInfixOf listA (tail listB)

helpFunction :: (Eq a) => [a] -> [a] -> Bool helpFunction [] [] = True helpFunction [] list = True helpFunction list [] = False helpFunction (x:xs)(y:ys) | x == y = helpFunction xs ys | otherwise = False

i did the开发者_开发技巧 help function, because i need the first element of the myIsInfixOf Function, untouchable.

if i don't make this helpFunction, the first element of the function myIsInfixOf, always decrease by one element, which is not good, because i need to iterate throughout the whole second element of the function myIsInfixOf, and check for equality with the first element of it.

with the help of the helpFunction, my first element of the list is untouchable and just the second element is decreasing every recursion(which is good).

so, can i save somewhere, my first element of myIsInfixOf, without recode almost everything?

thanks. :-)


The two functions aren't really all that similar, if you look at them. What is the same are the first three "trivial" cases, but the last case does different things in both functions. You could also leave out the first two cases in either of those functions since they check the same thing on the same lists. So myIsInfixOf also works like this:

myIsInfixOf :: (Eq a) => [a] -> [a] -> Bool
myIsInfixOf (a:as) [] = False
myIsInfixOf listA listB | helpFunction listA listB = True
                        | otherwise =  myIsInfixOf listA (tail listB)

This really isn't the same as helpFunction, and doesn't repeat any nontrivial code.

Also you really want the second function to work independently from the first, since you want to check for every position in listB if every character of listA matches those in listB. To do this in a imperative program you would need nested loops, here you need a nested recursion best done with a helper function like you did. The issue is not that listA would somehow be lost without the helpFunction, the problem is that the algorithm requires helpFunction to run over the list independently of myIsInfixOf.

If you want to avoid manually implementing the recursion of myIsInfixOf by using more functions from the standard library you could use any and tails. For helpFunction probably explicit recursion is the way to go, but you could simplify the whole last case to:

helpFunction (x:xs) (y:ys) = (x == y) && helpFunction xs ys


Note that 1) you don't need the first clause in both cases, since [] list matches [] [] as well and you return the same result; 2) helpFunction listA listB == True is the same as helpFunction listA listB.

myIsInfixOf :: (Eq a) => [a] -> [a] -> Bool
myIsInfixOf [] list = True
myIsInfixOf list [] = False
myIsInfixOf listA listB | helpFunction listA listB = True
                        | otherwise =  myIsInfixOf listA (tail listB)

helpFunction :: (Eq a) => [a] -> [a] -> Bool
helpFunction [] list    = True
helpFunction list []    = False
helpFunction (x:xs)(y:ys) | x == y = helpFunction xs ys
                          | otherwise = False

In the comment you said

the help function examine if the first element is inside the second one.

Actually, it doesn't. It checks if the second argument starts with the first one. That's why you need a different function. So a better name for helpFunction is myPrefixOf. This should help you eliminate another clause from the definition of myIsInfixOf.


In line with a few of the suggestions Alexey Romanov and sth made, this would be my initial take on rewriting it:

import Data.List

myIsInfixOf xs ys = any (myIsPrefixOf xs) (tails ys)

myIsPrefixOf [] _ = True
myIsPrefixOf (x:_) [] = False
myIsPrefixOf (x:xs) (y:ys) = x == y && myIsPrefixOf xs ys

To more directly answer your actual question, note two things about this version:

  • You can kind of "save" the value of the first argument using partial application
  • You can eliminate a lot of the redundant code by using built-in recursive functions


I think you're confusing 'element' and 'argument' in your question, at least in some places. Also, what do you mean by 'untouchable'?

To come back to your question: You can do a pattern match and keep the original argument around by using so-called at-patterns:

myIsInfixOf listA@(x:xs) listB@(y:ys) = ...

This lets you refer to the entire first argument as listA, the first element of listA as x and the tail as xs (and same for the second argument). Is that what you meant?

0

精彩评论

暂无评论...
验证码 换一张
取 消