haskell infinite list of incrementing pairs

2019-02-18 15:42发布

问题:

Create an infinite list pairs :: [(Integer, Integer)] containing pairs of the form (m,n), where each of m and n is a member of [0 ..]. An additional requirement is that if (m,n) is a legit member of the list, then (elem (m,n) pairs) should return True in finite time. An implementation of pairs that violates this requirement is considered a non- solution. *Fresh edit Thank you for the comments, Lets see if I can make some progress*

    pairs :: [(Integer, Integer)]
    pairs = [(m,n) | t <- [0..], m <- [0..], n <-[0..], m+n == t]

Something like this? I just don't know where it's going to return True in finite time.

I feel the way the question is worded elem doesn't have to be part of my answer. Just if you call (elem (m,n) pairs) it should return true. Sound right?

回答1:

Ignoring the helper method, the list comprehension you have will list out all pairs but the order of elements is a problem. You'll have a infinitely many pairs like (0, m) which are followed by infinitely many pairs like (1, m). Of course elem will forever iterate all the (0, m) pairs never reaching (1, m) or (2, m) etc.

I'm not sure why you have the helper method -- with it, you are only building a list of pairs like [(0,0), (1,1), (2,2), ...] because you've filtered on m = n. Was that part of the requirements?

Like @hammar suggested, start with 0 = m + n and list out the pairs (m, n). Then list pairs (m, n) where 1 = m + n. Then your list will look like [(0,0), (0,1), (1,0), (0,2), (1,1), (2,0), ...].



回答2:

The helper function ensures that pairs is a list of the form [ (0,0) , (1,1) , (2,2) ... ].

So elem ( m , n ) pairs can be implemented as:

elem (m , n) _ |  m == n    = True
               |  otherwise = False

This is a constant time implementation.



回答3:

I first posted

Prelude> let pairs = [(m, n) | t <- [0..]
                     , let m = head $ take 1 $ drop t [0..] 
                     , let n = head $ take 1 $ drop (t + 1) [0..]]

Which, I believed answered the three conditions set by the professor. But hammar pointed out that if I chose this list as an answer, that is, the list of pairs of the form (t, t+1), then I might as well choose the list

repeat [(0,0)] 

Well, both of these do seem to answer the professor's question, considering there seems to be no mention of the list having to contain all combinations of [0..] and [0..].

That aside, hammer helped me see how you can list all combinations, facilitating the evaluation of elem in finite time by building the infinite list from finite lists. Here are two other finite lists - less succinct than Hammar's suggestion of the diagonals - that seem to build all combinations of [0..] and [0..]:

edges = concat [concat [[(m,n),(n,m)] | let m = t, n <- take m [0..]] ++ [(t,t)] 
      | t <- [0..]]


*Main> take 9 edges
[(0,0),(1,0),(0,1),(1,1),(2,0),(0,2),(2,1),(1,2),(2,2)]

which construct the edges (t, 0..t) (0..t, t), and

oddSpirals size = concat [spiral m size' | m <- n] where
  size' = if size < 3 then 3 else if even size then size - 1 else size
  n = map (\y -> (fst y * size' + div size' 2, snd y * size' + div size' 2)) 
          [(x, t-x) | let size' = 5, t <- [0..], x <- [0..t]]
  spiral seed size = spiral' (size - 1) "-" 1 [seed]
  spiral' limit op count result
    | count == limit =
       let op' = if op == "-" then (-) else (+)
           m = foldl (\a b -> a ++ [(op' (fst $ last a) b, snd $ last a)]) result (replicate count 1)
           nextOp = if op == "-" then "+" else "-"
           nextOp' = if op == "-" then (+) else (-)
           n = foldl (\a b -> a ++ [(fst $ last a, nextOp' (snd $ last a) b)]) m (replicate count 1)
           n' = foldl (\a b -> a ++ [(nextOp' (fst $ last a) b, snd $ last a)]) n (replicate count 1)
       in n'
    | otherwise      =
        let op' = if op == "-" then (-) else (+)
            m = foldl (\a b -> a ++ [(op' (fst $ last a) b, snd $ last a)]) result (replicate count 1)
            nextOp = if op == "-" then "+" else "-"
            nextOp' = if op == "-" then (+) else (-)
            n = foldl (\a b -> a ++ [(fst $ last a, nextOp' (snd $ last a) b)]) m (replicate count 1)
        in spiral' limit nextOp (count + 1) n


*Main> take 9 $ oddSpirals 3
[(1,1),(0,1),(0,2),(1,2),(2,2),(2,1),(2,0),(1,0),(0,0)]

which build clockwise spirals of length 'size' squared, superimposed on hammar's diagonals algorithm.