是(map f)== concatMap(map f。(:[]))?

时间:2011-08-01 04:35:38

标签: haskell arrows

我为left类的流函数(SF)定义了right / ArrowChoice方法,如下所示: newtype SF a b = SF { runSF :: [a] -> [b] }

instance ArrowChoice SF where
  left (SF f) =
   SF $ map (either (\x -> Left . head $ f [x]) Right)
  right (SF f) =
   SF $ map (either Left (\x -> Right . head $ f [x]))

ghci中的一些测试看起来好像一切都很好:

λ> let lst = [Left 'c', Right 2, Left 'a', Right 3, Left 't']
λ> let foo = SF $ map toUpper
λ> let bar = SF $ map (+1)
λ> runSF (left foo) lst
[Left 'C',Right 2,Left 'A',Right 3,Left 'T']
λ> runSF (right bar) lst
[Left 'c',Right 3,Left 'a',Right 4,Left 't']

但与mapA一起使用则说不然:

λ> let delay x = SF $ init . (x:)
λ> runSF (mapA (delay 0)) [[1,2,3],[4,5,6],[7,8,9]]
[[0,0,0],[0,0,0],[0,0,0]]

正确的答案应该是:

[[0,0,0],[1,2,3],[4,5,6]]

其中mapA定义为:

mapA :: ArrowChoice arr => arr a b -> arr [a] [b]
mapA f = arr listcase >>>
         (arr (const []) ||| (f *** mapA f >>> arr (uncurry (:))))

1 个答案:

答案 0 :(得分:7)

我认为您的ArrowChoice实例不正确。

注意delay函数接受一个流并替换第一个元素;关键的是,它并没有完全相同地对待所有元素。现在,请考虑您对Left

的定义
left (SF f) = SF $ map (either (\x -> Left . head $ f [x]) Right)

观察f是整个流函数的内容,因此根据流的位置可能会有不同的行为。 left函数然后创建一个新的流函数,在其流上映射一个同类函数,其中每个元素都通过(对于Right s)或提升到单例输入流函数运行的列表。

而不是delay,而是考虑以下函数:

skip = SF $ drop 1

这完全删除了流的第一个元素,并且由于left每次在单个列表上独立运行其输入,这将完全过滤掉所有Left个!可能不是你想要的。

相反,您需要执行诸如将流分区为其LeftRight组件之类的操作,将输入流功能应用于{{1}的整个流然后,将lefts和权利以原来相同的顺序合并在一起。

我得到的印象是你正在做这种运动,所以我不会通过简单地完全解决问题来破坏乐趣。但我会说我的代码确实在你的例子中给出了Left


如果您确实想查看我的测试代码,请点击下方。 (嘘,它藏起来了)

  

 instance ArrowChoice SF where
     left (SF f) = SF $ \xs -> let (ls, rs) = partitionEithers xs 
                               in merge xs (f ls) rs
 
 merge (Left  _:xs) (l:ls) rs = Left l  : merge xs ls rs
 merge (Right _:xs) ls (r:rs) = Right r : merge xs ls rs
 merge _ _ _ = []