`DoNotUnboxLazy`'s `elemseq` forces an element that `fromList` stores unevaluated
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 50/100
Hướng nghiên cứu
The suspect is the G.Vector instance for DoNotUnboxLazy in vector/src/Data/Vector/Unboxed/Unsafe.hs (lines 882-895 on master; Base.hs at the pinned commit), where elemseq _ = seq is defined. Start by running the Repro.hs program from the issue to confirm which functions force the element. Done means singleton, replicate, cons, snoc and constructN no longer force a DoNotUnboxLazy element, and the existing tests still pass.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
I'm not 100% sold on this, but my bot (Claude Opus 5.5) says it's important, so here it goes:
Summary
Data.Vector.Unboxed stores a DoNotUnboxLazy element in a boxed Data.Vector, and a write into that vector does not evaluate the element. The documentation of DoNotUnboxLazy says that the newtype "does not alter the strictness semantics of the underlying type". But its G.Vector instance in Data.Vector.Unboxed.Base defines elemseq _ = seq (lines 842-855). The documentation of elemseq in Data.Vector.Generic.Base says that it evaluates the element "as far as storing it in a vector would" (lines 140-152).
singleton, replicate, cons, snoc, constructN and constructrN call elemseq before they store an element (see singleton). Because of this, they evaluate a DoNotUnboxLazy element to weak head normal form. fromList and generate do not call elemseq, and they store the same element unevaluated. A tuple gives elemseq to each component, so a DoNotUnboxLazy component of a tuple is also evaluated. The boxed Data.Vector keeps the default elemseq, which does not evaluate the element.
The table gives the result of the program in "Steps to reproduce" for the element e = DoNotUnboxLazy undefined.
| Function | Element evaluated |
|---|---|
fromList [e], generate 1 (const e) |
no |
singleton e, replicate 3 e, cons e empty, snoc empty e, constructN 1 (const e) |
yes |
singleton (0, e) |
yes |
Data.Vector: singleton undefined, cons undefined empty |
no |
Proposed fix
Remove elemseq _ = seq from the G.Vector instance of DoNotUnboxLazy. Then the class default, elemseq _ = \_ x -> x, applies, as for Data.Vector. On master at d0f42e0562, the instance is in Data.Vector.Unboxed.Unsafe (lines 882-895) and has the same code.
The two other newtypes do not need a change. DoNotUnboxStrict stores its elements through Data.Vector.Strict, whose write evaluates the element to weak head normal form, as its elemseq _ = seq does. DoNotUnboxNormalForm stores force x, and its elemseq uses rnf.
Until vector has a fix, use fromList or generate, not singleton or replicate, to keep the element unevaluated.
Steps to reproduce
-
Save the program below as
Repro.hs. -
Run it. To select a compiler, add
-w ghc-VERSION. For GHC HEAD, whosebaseis newer than vector-0.13.2.0 permits, I also added--allow-newer=base,ghc-prim,ghc-bignum,template-haskell,containers.
cabal run -v0 Repro.hs
- On GHC HEAD 10.1.20260918, the output is below. With
ghc-options: -O0in the script header, the output is the same.
Data.Vector.Unboxed, DoNotUnboxLazy undefined:
fromList [e] : element not forced
generate 1 (const e) : element not forced
singleton e : element forced
replicate 3 e : element forced
cons e empty : element forced
snoc empty e : element forced
constructN 1 (const e): element forced
singleton (0, e) : element forced
Data.Vector, undefined:
singleton undefined : element not forced
cons undefined empty : element not forced
{- cabal:
build-depends: base, vector ==0.13.2.0
-}
-- Reproducer: DoNotUnboxLazy's elemseq forces the element, so singleton,
-- replicate, cons, snoc and constructN force an element that fromList
-- and generate store unevaluated. The boxed Data.Vector is the control.
--
-- Run: cabal run -v0 Repro.hs
{-# LANGUAGE ScopedTypeVariables #-}
module Main (main) where
import Control.Exception (ErrorCall, evaluate, try)
import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as VU
e :: VU.DoNotUnboxLazy Int
e = VU.DoNotUnboxLazy undefined
check :: String -> Int -> IO ()
check name n = do
r <- try (evaluate n)
putStrLn $ name ++ ": " ++ case r of
Left (_ :: ErrorCall) -> "element forced"
Right _ -> "element not forced"
main :: IO ()
main = do
putStrLn "Data.Vector.Unboxed, DoNotUnboxLazy undefined:"
check " fromList [e] " $ VU.length (VU.fromList [e])
check " generate 1 (const e) " $ VU.length (VU.generate 1 (const e))
check " singleton e " $ VU.length (VU.singleton e)
check " replicate 3 e " $ VU.length (VU.replicate 3 e)
check " cons e empty " $ VU.length (VU.cons e VU.empty)
check " snoc empty e " $ VU.length (VU.snoc VU.empty e)
check " constructN 1 (const e)" $ VU.length (VU.constructN 1 (const e))
check " singleton (0, e) " $ VU.length (VU.singleton (0 :: Int, e))
putStrLn "Data.Vector, undefined:"
check " singleton undefined " $ V.length (V.singleton (undefined :: Int))
check " cons undefined empty " $ V.length (V.cons (undefined :: Int) V.empty)
Expected behavior
singleton, replicate, cons, snoc and constructN store a DoNotUnboxLazy element as fromList does, and do not evaluate it.
Environment
- vector-0.13.2.0, from Hackage. On master at d0f42e0562, the instance has the same code, in
Data.Vector.Unboxed.Unsafe. - GHC HEAD 10.1.20260918 (commit 6913545fd3); cabal-install 3.18.1.0.
- Linux (kernel 7.0.0-34-generic), x86_64 (AMD Ryzen 7 5800X).
- Ngôn ngữ chính
- Haskell
- Star
- 403
- Fork
- 146
- Merge trung bình
- 1 ngày 22 giờ
- Pull request đã merge (30 ngày)
- 3
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của haskell/vector
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 68/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 45/100
-
`Size` can be a newtype.Đang mở
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 35/100
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 55/100
-
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 35/100
Tất cả issue của haskell/vector
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
halogenandtoast/ArkhamHorror#5825 · 1 bình luận ·
-
docs: install-manifest download links use main instead of master (404)Có thể đã có người làm @ChinmayaBisoi đã nhận 1 ngày trước. Đang mở
Độ khó 2/5 Dưới một giờ Mức phù hợp với người mới 78/100
hasura/graphql-engine#10884 ·
-
New-pipeline: update TracyĐang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
AccelerateHS/accelerate#583 · 2 bình luận ·
-
component: hls-refactor-plugin status: needs triage type: bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 60/100
haskell/haskell-language-server#5111 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
enhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
alunduil/network-arbitrary#193 ·
Maintainer thường phản hồi trong vòng 1 ngày