Output an element the number of times I want

前端 未结 6 1903
-上瘾入骨i
-上瘾入骨i 2021-01-21 03:11

I have this code:

lado ::  [([Char],Int)] -> [[Char]]
lado xs = [a | (a,b) <- xs]

I need to output this:

> lado [("A         


        
6条回答
  •  半阙折子戏
    2021-01-21 03:39

    Will Ness came up with a nice expression in terms of rotations:

    lado ::  [(a,Int)] -> [a]
    lado []        = []
    lado ((a,1):b) = a : lado b
    lado ((a,n):b) = a : lado (b ++ [(a,n-1))])
    

    Unfortunately, this will be quite inefficient because using ++ to add an element to the end of a list takes linear time. This can be fixed by using a queue instead of a list. The queue is used in an ephemeral manner, so it can be a very simple one:

    -- Invariant: The Int is at least 1.
    data IStream a
      = ISCons a !Int (IStream a)
      | ISNil
    
    -- Invariant: The Int is at least 1.
    data IList a
      = ICons a !Int !(IList a)
      | INil
    
    data IQueue a = IQueue !(IStream a) !(IList a)
    
    -- Note: the list may be infinite
    listToIStream :: [(a, Int)] -> IStream a
    listToIStream = foldr go ISNil
      where
        go (a, n) r
          | n <= 0 = r
          | otherwise = ISCons a n r
    
    listToIQueue :: [(a, Int)] -> IQueue a
    listToIQueue xs = IQueue (listToIStream xs) INil
    
    dequeue :: IQueue a -> Maybe (Dequeued a)
    dequeue (IQueue (ISCons a i more) rear) = Just (Dequeued a i (IQueue more rear))
    dequeue (IQueue ISNil INil) = Nothing
    dequeue (IQueue ISNil (ICons a i more)) = Just $! (rotate ISNil a i more)
    
    data Dequeued a = Dequeued a !Int !(IQueue a)
    
    rotate :: IStream a -> a -> Int -> IList a -> Dequeued a
    rotate str a0 i0 INil = Dequeued a0 i0 (IQueue str INil)
    rotate str a0 i0 (ICons a i more) = rotate (ISCons a0 i0 str) a i more
    
    enqueue :: IQueue a -> a -> Int -> IQueue a
    enqueue (IQueue front rear) a i = IQueue front (ICons a i rear)
    

    Now we can define

    lado :: [(a, Int)] -> [a]
    lado = lado' . listToIQueue
    
    lado' :: IQueue a -> [a]
    lado' q = case dequeue q of
      Nothing -> []
      Just (Dequeued a 1 b) -> a : lado' b
      Just (Dequeued a n b) -> a : lado' (enqueue b a (n - 1))
    

提交回复
热议问题