简体   繁体   中英

Writing a recursive function with condition In Haskell:

I want a function f::[type]->[type] that is recursive defined roughly like this :

It starts with a list with 1 element x . Then it applies 3 "generator functions" lets call them generatorA , generatorB , and generator C , all functions ::type->type , and adds those to the list IF they accept some condition. for each accepted generated number, it repeats applying generator A , B and C and test conditions until condition test is false. So for each element accepted to the list, 3 new elements will be generated and tested for list.

An example would be:

f::[int]->[Int]

generatorA x = x+1

generatorB x = 2x+1

generatorC x = 3x+1

Condition: Must be composite number (not prime).

computing f [10] it should start generatorA 10 = 11 , discard that.

generatorB 10 = 21 accept and then:

  • generatorA 21 = 22 accept and then:
    • generatorA 22 = 23 prime discard.
  • generatorB 21 = 43 discard
  • generatorC 21 = 64 accept and etc. etc. etc.

Question is: How do i code the function f ? I have no idea how to even begin. my best guess was

 f (x:xs)
       |condition==True   = (something something)
       |otherwise         = xs
       where
         a=generatorA x
         b=generatorB x
         c=generatorC x

thanks for your help.

If it starts with a singleton list it might as well start with a single value as its argument.

ga x = [y | let y=x+1, composite y] >>= (\x-> x:f x)
gb x = [y | let y=2*x+1, composite y] >>= (\x-> x:f x)
gc x = [y | let y=3*x+1, composite y] >>= (\x-> x:f x)

f :: Integer -> [Integer]
f x = ga x ++ gb x ++ gc x

I use Integer s to avoid overflow issues. Testing:

*Main> take 40 $ f 10
[21,22,45,46,93,94,95,96,289,290,291,292,585,586,1173,1174,1175,1176,1177,1178,1
179,1180,2361,2362,2363,2364,2365,2366,2367,2368,2369,2370,4741,4742,4743,4744,4
745,4746,4747,4748]

f can also be implemented to produce the results in shallower fashion,

import Data.List

f x = concat $ transpose [ga x, gb x, gc x]

Testing:

*Main> take 80 $ h 10
[21,22,64,45,65,46,129,91,66,136,130,93,196,92,259,273,133,94,388,183,393,274,26
1,187,134,274,260,820,589,280,777,93,267,275,391,95,394,184,519,1641,400,188,116
5,275,590,549,262,561,135,185,778,2461,1180,189,778,550,268,276,392,375,1179,549
,261,1642,801,841,1166,94,395,550,784,96,403,185,520,2462,1768,562,1555,276]

use Data.Tree.unfoldTree :: (b -> (a, [b])) -> b -> Tree a to build your list of values. then use flatten if you want preorder, or concat . Data.Tree.levels concat . Data.Tree.levels to have a breadth first order.

f x = flatten $ unfoldTree (\b -> (b, filter composite (map ($ b) [ga, gb, gc]))) x

this list will include the initial seed element, if you don't want that element. just call tail .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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