【发布时间】:2019-08-22 05:43:24
【问题描述】:
我正在按照教程programming with arrows 学习Arrow。我根据论文输入了以下代码,除了 SF 是由 data 定义的,而不是像论文中那样由 newtype 定义(实际上,我做了这个更改是偶然的,因为我输入了内存中的代码):
import Control.Category
import Control.Arrow
import Prelude hiding (id, (.))
data SF a b = SF { runSF :: [a] -> [b] } -- this is the change, using data instead of newtype as in the paper
-- The folowing code is the same as in the paper
instance Category SF where
id = SF $ \x -> x
(SF f) . (SF g) = SF $ \x -> f (g x)
instance Arrow SF where
arr f = SF $ map f
first (SF f) = SF $ unzip >>> first f >>> uncurry zip
instance ArrowChoice SF where
left (SF f) = SF $ \xs -> combine xs (f [y | Left y <- xs])
where
combine (Left _ : ys) (z:zs) = Left z : combine ys zs
combine (Right y : ys) zs = Right y : combine ys zs
combine [] _ = []
delay :: a -> SF a a
delay x = SF $ init . (x:)
mapA :: ArrowChoice a => a b c -> a [b] [c]
mapA f = arr listcase >>>
arr (const []) ||| (f *** mapA f >>> arr (uncurry (:)))
listcase :: [a] -> Either () (a, [a])
listcase [] = Left ()
listcase (x:xs) = Right (x, xs)
当我在ghci 中加载文件并执行runSF (mapA (delay 0)) [[1,2,3],[4,5,6]] 时,它会触发无限循环并最终耗尽内存。如果我将data 改回newtype,一切正常。同样的问题发生在 ghc 8.0.2、8.2.2 和 8.6.3 中。
即使我将代码编译成可执行文件,也存在同样的问题。
我认为data 和newtype 之间的区别,在定义只有一个字段的数据结构时,就是运行时成本。但这个问题似乎暗示了它们之间的更多差异。或者可能有一些我没有注意到 Arrow 类型类的东西。
任何人都可以有任何想法吗?非常感谢!
【问题讨论】:
-
我认为这与提供惰性值构造函数的数据有关,newtype 是严格的。例如,请参阅 Rose 对 stackoverflow.com/questions/2649305/… 的回答。也许更熟悉的人可以通过代码并给出更准确的答案。