Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

`DoNotUnboxLazy`'s `elemseq` forces an element that `fromList` stores unevaluated

Ouverte
#575 4 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

@Shimuuar y travaille déjà.

Depuis le 14/10/2026.

  • #577 par @Shimuuar — ouverte

Évaluation

Difficulté
2/5
Temps estimé
1-3 heures
Accessibilité débutants
50/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
haskell
Domaine
data

Piste de recherche

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.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

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

  1. Save the program below as Repro.hs.

  2. Run it. To select a compiler, add -w ghc-VERSION. For GHC HEAD, whose base is 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
  1. On GHC HEAD 10.1.20260918, the output is below. With ghc-options: -O0 in 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).
Langage dominant
Haskell
Étoiles
404
Forks
146
Merge moyen
1 j 22 h
PR mergées (30 j)
3

Préparer son environnement

Ce projet ne fournit ni conteneur de développement, ni Dockerfile, ni guide de contribution : l'installation est à votre charge. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de haskell/vector

Toutes les issues de haskell/vector

Issues similaires

Plus d'issues Haskell

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.