packages feed

linear-base 0.6.0 → 0.7.0

raw patch · 12 files changed

+308/−5 lines, 12 filesdep +bytestringdep ~basePVP ok

version bump matches the API change (PVP)

Dependencies added: bytestring

Dependency ranges changed: base

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,16 @@ # Change Log +## [v0.7.0](https://github.com/tweag/linear-base/tree/v0.7.0) (2026-02-27)++[Full Changelog](https://github.com/tweag/linear-base/compare/v0.6.0...v0.7.0)++### Headline changes++- Add instance Consumable/Dupable/Movable for ByteString, ShortByteString and Text [\#501](https://github.com/tweag/linear-base/pull/501) ([Bodigrim](https://github.com/Bodigrim))+- feat: Adds missing instances for `NonEmpty` and adds some Linear counterpart of `Data.List.NonEmpty` [\#495](https://github.com/tweag/linear-base/pull/495) ([konn](https://github.com/konn))+- use Unsatisfiable for banned instances \(unrestricted Monoid / Semigroup for linear containers\) [\#494](https://github.com/tweag/linear-base/pull/494) ([konn](https://github.com/konn))+- Control Monad instance for linear arrows [\#493](https://github.com/tweag/linear-base/pull/493) ([konn](https://github.com/konn))+ ## [v0.6.0](https://github.com/tweag/linear-base/tree/v0.6.0) (2025-11-18)  [Full Changelog](https://github.com/tweag/linear-base/compare/v0.5.0...v0.6.0)
linear-base.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               linear-base-version:            0.6.0+version:            0.7.0 license:            MIT license-file:       LICENSE copyright:          (c) Tweag Holding and affiliates@@ -79,6 +79,7 @@         Data.HashMap.Mutable.Linear         Data.HashMap.Mutable.Linear.Internal         Data.List.Linear+        Data.List.NonEmpty.Linear         Data.Maybe.Linear         Data.Monoid.Linear         Data.Monoid.Linear.Internal.Monoid@@ -134,6 +135,7 @@     default-language: Haskell2010     build-depends:         base >=4.16 && <5,+        bytestring,         containers,         ghc-prim,         ghc-bignum,
src/Control/Functor/Linear/Internal/Reader.hs view
@@ -1,5 +1,9 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE FlexibleInstances #-} {-# OPTIONS -Wno-orphans #-} {-# LANGUAGE LinearTypes #-}+{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE NoImplicitPrelude #-} {-# OPTIONS_HADDOCK hide #-} @@ -28,8 +32,10 @@ import Data.Functor.Identity import qualified Data.Functor.Linear.Internal.Applicative as Data import qualified Data.Functor.Linear.Internal.Functor as Data+import Data.Kind (FUN) import Data.Unrestricted.Linear.Internal.Consumable import Data.Unrestricted.Linear.Internal.Dupable+import GHC.Exts (Multiplicity (..)) import Prelude.Linear.Internal (runIdentity', ($), (.))  -- # Linear ReaderT@@ -119,3 +125,9 @@  instance MonadTrans (NonLinear.ReaderT r) where   lift x = NonLinear.ReaderT (\_ -> x)++deriving via Reader r instance (Dupable r) => Data.Applicative (FUN 'One r)++deriving via Reader r instance (Dupable r) => Applicative (FUN 'One r)++deriving via Reader r instance (Dupable r) => Monad (FUN 'One r)
src/Data/Functor/Linear/Internal/Functor.hs view
@@ -32,6 +32,7 @@ import Data.Functor.Product import Data.Functor.Sum import Data.Kind (FUN)+import Data.List.NonEmpty (NonEmpty) import Data.Unrestricted.Linear.Internal.Consumable import Data.Unrestricted.Linear.Internal.Ur import GHC.Types (Multiplicity (..))@@ -75,6 +76,11 @@       go :: [a] %1 -> [b]       go [] = []       go (a : as) = f a : go as++deriving via+  Generically1 NonEmpty+  instance+    Functor NonEmpty  deriving via   Generically1 (Const x)
src/Data/Functor/Linear/Internal/Traversable.hs view
@@ -34,6 +34,7 @@ import Data.Functor.Const import qualified Data.Functor.Linear.Internal.Applicative as Data import qualified Data.Functor.Linear.Internal.Functor as Data+import Data.List.NonEmpty (NonEmpty (..)) import GHC.Types (Multiplicity (..)) import Generics.Linear import Prelude.Linear.Internal@@ -130,6 +131,12 @@     where       go [] = Control.pure []       go (x : xs) = Control.liftA2 (:) (f x) (go xs)++instance Traversable NonEmpty where+  -- We define traverse explicitly both to allow specialization+  -- to the appropriate Applicative and to allow specialization to+  -- the passed function. The generic definition allows neither, sadly.+  traverse f (x :| xs) = (:|) Control.<$> f x Control.<*> traverse f xs  instance Traversable ((,) a) where   traverse = genericTraverse
src/Data/HashMap/Mutable/Linear/Internal.hs view
@@ -1,5 +1,7 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE InstanceSigs #-}@@ -25,7 +27,9 @@ import Data.Hashable import qualified Data.Maybe as NonLinear import Data.Unrestricted.Linear+import GHC.TypeLits (ErrorMessage (..)) import Prelude.Linear hiding (filter, insert, lookup, mapMaybe, read, (+))+import Prelude.Linear.Unsatisfiable (Unsatisfiable, unsatisfiable) import Unsafe.Coerce (unsafeCoerce) import qualified Unsafe.Linear as Unsafe import Prelude ((+))@@ -481,8 +485,8 @@         )         arr -instance Prelude.Semigroup (HashMap k v) where-  (<>) = error "Prelude.<>: invariant violation, unrestricted HashMap"+instance (Unsatisfiable ('Text "Using Prelude's Semigroup methods on a Data.HashMap.Mutable.Linear is vacuous as there can't be an unrestricted such Hashmap")) => Prelude.Semigroup (HashMap k v) where+  (<>) = unsatisfiable  instance (Keyed k) => Semigroup (HashMap k v) where   (<>) = union
+ src/Data/List/NonEmpty/Linear.hs view
@@ -0,0 +1,211 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE LinearTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# OPTIONS_GHC -Wno-name-shadowing #-}+{-# OPTIONS_GHC -Wno-orphans #-}++-- |+-- Linear versions of 'NonEmpty' functions.+--+-- This module only contains minimal amount of documentation; consult the+-- original "Data.List.NonEmpty" module for more detailed information.+module Data.List.NonEmpty.Linear+  ( -- * Non-empty stream transformations+    NonEmpty (..),+    map,+    intersperse,+    scanl,+    scanr,+    scanl1,+    scanr1,+    transpose,+    NonLinear.sortBy,+    NonLinear.sortWith,++    -- * Basic functions+    length,+    NonLinear.head,+    NonLinear.tail,+    NonLinear.last,+    NonLinear.init,+    singleton,+    (<|),+    cons,+    uncons,+    unfoldr,+    NonLinear.sort,+    reverse,+    append,+    appendList,+    prependList,++    -- * Extracting sublists+    take,+    drop,+    splitAt,+    takeWhile,+    dropWhile,+    span,+    break,+    filter,+    partition,++    -- * Zipping and unzipping streams+    zip,+    zipWith,+    zip',+    zipWith',+    unzip,+    unzip3,++    -- * Converting to and from a list+    fromList,+    toList,+    nonEmpty,+    xor,+  )+where++import qualified Data.List.Linear as List+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NonLinear+import Data.Vector.Internal.Check (HasCallStack)+import Prelude.Linear hiding (drop, dropWhile, filter, intersperse, length, map, partition, reverse, scanl, scanl1, scanr, scanr1, span, splitAt, take, takeWhile, transpose, uncons, unfoldr, unzip, unzip3, zip, zip', zipWith, zipWith')+import qualified Unsafe.Linear as Unsafe+import qualified Prelude as Prelude++map :: (a %1 -> b) -> NonEmpty a %1 -> NonEmpty b+map f (x :| xs) = f x :| List.map f xs++intersperse :: a -> NonEmpty a %1 -> NonEmpty a+intersperse a = Unsafe.toLinear (NonLinear.intersperse a)++reverse :: NonEmpty a %1 -> NonEmpty a+reverse = Unsafe.toLinear NonLinear.reverse++scanl :: (Dupable b) => (b %1 -> a %1 -> b) -> b %1 -> NonEmpty a %1 -> NonEmpty b+scanl f z = fromList . List.scanl f z . toList++scanr :: (Dupable b) => (a %1 -> b %1 -> b) -> b %1 -> NonEmpty a %1 -> NonEmpty b+scanr f z = fromList . List.scanr f z . toList++scanl1 :: (Dupable a) => (a %1 -> a %1 -> a) -> NonEmpty a %1 -> NonEmpty a+scanl1 f (x :| xs) = fromList $ List.scanl f x xs++scanr1 :: (Dupable a) => (a %1 -> a %1 -> a) -> NonEmpty a %1 -> NonEmpty a+scanr1 f (x :| xs) = fromList $ List.scanr1 f (x : xs)++transpose :: NonEmpty (NonEmpty a) %1 -> NonEmpty (NonEmpty a)+transpose = Unsafe.toLinear NonLinear.transpose++singleton :: a %1 -> NonEmpty a+singleton = (:| [])++infixr 5 <|++(<|) :: a %1 -> NonEmpty a %1 -> NonEmpty a+a <| bs = a :| toList bs++cons :: a %1 -> NonEmpty a %1 -> NonEmpty a+cons = (<|)++uncons :: NonEmpty a %1 -> (a, Maybe (NonEmpty a))+uncons (x :| xs) = (x, nonEmpty xs)++unfoldr :: (a %1 -> (b, Maybe a)) -> a %1 -> NonEmpty b+unfoldr f a = case f a of+  (b, mc) -> b :| maybe [] go mc+  where+    go c = case f c of+      (d, me) -> d : maybe [] go me++append :: NonEmpty a %1 -> NonEmpty a %1 -> NonEmpty a+append = (<>)++appendList :: NonEmpty a %1 -> [a] %1 -> NonEmpty a+appendList (x :| xs) ys = x :| (xs <> ys)++prependList :: [a] %1 -> NonEmpty a %1 -> NonEmpty a+prependList ls ne = case ls of+  [] -> ne+  (y : ys) -> y :| (ys <> toList ne)++-- | __NOTE__: This does not short-circuit and always traverses the+-- entire list to consume the rest of the elements.+take :: (Consumable a) => Int -> NonEmpty a %1 -> [a]+take n = List.take n . toList++drop :: (Consumable a) => Int -> NonEmpty a %1 -> [a]+drop n = List.drop n . toList++splitAt :: (Consumable a) => Int -> NonEmpty a %1 -> ([a], [a])+splitAt n = List.splitAt n . toList++-- | __NOTE__: This does not short-circuit and always traverses the+-- entire list to consume the rest of the elements.+takeWhile :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> [a]+takeWhile p = List.takeWhile p . toList++dropWhile :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> [a]+dropWhile p = List.dropWhile p . toList++span :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> ([a], [a])+span p = List.span p . toList++break :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> ([a], [a])+break p = span (not . p)++filter :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> [a]+filter p = List.filter p . toList++partition :: (Dupable a) => (a %1 -> Bool) -> NonEmpty a %1 -> ([a], [a])+partition p = List.partition p . toList++-- | Return the length of the given list alongside with the list itself.+length :: NonEmpty a %1 -> (Ur Int, NonEmpty a)+length = Unsafe.toLinear $ \xs ->+  (Ur (NonLinear.length xs), xs)++fromList :: (HasCallStack) => [a] %1 -> (NonEmpty a)+fromList (x : xs) = x :| xs+fromList [] = Prelude.error "NonEmpty.Linear.fromList: empty list"++toList :: NonEmpty a %1 -> [a]+toList (x :| xs) = x : xs++nonEmpty :: [a] %1 -> Maybe (NonEmpty a)+nonEmpty (x : xs) = Just (x :| xs)+nonEmpty [] = Nothing++xor :: NonEmpty Bool %1 -> Bool+xor = Unsafe.toLinear NonLinear.xor++zip :: (Consumable a, Consumable b) => NonEmpty a %1 -> NonEmpty b %1 -> NonEmpty (a, b)+zip = zipWith (,)++zipWith :: (Consumable a, Consumable b) => (a %1 -> b %1 -> c) -> NonEmpty a %1 -> NonEmpty b %1 -> NonEmpty c+zipWith f (a :| as) (b :| bs) = f a b :| List.zipWith f as bs++-- | Same as 'zipWith', but returns the leftovers instead of consuming them.+-- Because the leftovers are returned at toplevel, @zipWith'@ is pretty strict:+-- forcing the second cons cell of the returned list forces all the recursive+-- calls.+zipWith' :: (a %1 -> b %1 -> c) -> NonEmpty a %1 -> NonEmpty b %1 -> (NonEmpty c, Maybe (Either (NonEmpty a) (NonEmpty b)))+zipWith' f (a :| as) (b :| bs) =+  case List.zipWith' f as bs of+    (cs, may) -> (f a b :| cs, may)++-- | Same as 'zip', but returns the leftovers instead of consuming them.+zip' :: NonEmpty a %1 -> NonEmpty b %1 -> (NonEmpty (a, b), Maybe (Either (NonEmpty a) (NonEmpty b)))+zip' = zipWith' (,)++unzip :: NonEmpty (a, b) %1 -> (NonEmpty a, NonEmpty b)+unzip ((a, b) :| asbs) =+  List.unzip asbs & \(as, bs) ->+    (a :| as, b :| bs)++unzip3 :: NonEmpty (a, b, c) %1 -> (NonEmpty a, NonEmpty b, NonEmpty c)+unzip3 ((a, b, c) :| abs) =+  List.unzip3 abs & \(as, bs, cs) ->+    (a :| as, b :| bs, c :| cs)
src/Data/Monoid/Linear/Internal/Semigroup.hs view
@@ -11,6 +11,7 @@ module Data.Monoid.Linear.Internal.Semigroup   ( -- * Semigroup     Semigroup (..),+    sconcat,      -- * Endo     Endo (..),@@ -34,6 +35,7 @@ import Data.Functor.Const (Const (..)) import Data.Functor.Identity (Identity (..)) import qualified Data.Functor.Product as Functor+import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.Monoid as Monoid import Data.Ord (Down (..)) import Data.Proxy (Proxy (..))@@ -64,6 +66,13 @@ class Semigroup a where   (<>) :: a %1 -> a %1 -> a   infixr 6 <> -- same fixity as base.<>++sconcat :: (Semigroup a) => NonEmpty a %1 -> a+sconcat (x :| xs :: NonEmpty a) = go x xs+  where+    go :: a %1 -> [a] %1 -> a+    go acc [] = acc+    go acc (x' : xs') = go (acc <> x') xs'  -- | An @'Endo' a@ is just a linear function of type @a %1-> a@. -- This has a classic monoid definition with 'id' and '(.)'.
src/Data/Ord/Linear/Internal/Eq.hs view
@@ -13,6 +13,7 @@  import Data.Bool.Linear import Data.Int (Int16, Int32, Int64, Int8)+import Data.List.NonEmpty (NonEmpty (..)) import Data.Unrestricted.Linear import Data.Word (Word16, Word32, Word64, Word8) import Prelude.Linear.Internal@@ -46,6 +47,9 @@   [] == [] = True   (x : xs) == (y : ys) = x == y && xs == ys   xs == ys = (xs, ys) `lseq` False++instance (Consumable a, Eq a) => Eq (NonEmpty a) where+  (x :| xs) == (y :| ys) = x == y && xs == ys  instance (Consumable a, Eq a) => Eq (Prelude.Maybe a) where   Prelude.Nothing == Prelude.Nothing = True
src/Data/Ord/Linear/Internal/Ord.hs view
@@ -15,6 +15,7 @@  import Data.Bool.Linear (Bool (..), not) import Data.Int (Int16, Int32, Int64, Int8)+import Data.List.NonEmpty (NonEmpty (..)) import Data.Monoid.Linear import Data.Ord (Ordering (..)) import Data.Ord.Linear.Internal.Eq@@ -118,6 +119,10 @@     case compare x y of       EQ -> compare xs ys       res -> (xs, ys) `lseq` res++instance (Consumable a, Ord a) => Ord (NonEmpty a) where+  compare (x :| xs) (y :| ys) =+    compare x y <> compare xs ys  instance (Ord a, Ord b) => Ord (a, b) where   (a, b) `compare` (a', b') =
src/Data/Set/Mutable/Linear/Internal.hs view
@@ -1,10 +1,13 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE LinearTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StrictData #-} {-# LANGUAGE TupleSections #-}+{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE NoImplicitPrelude #-} {-# OPTIONS_GHC -Wno-name-shadowing #-} {-# OPTIONS_HADDOCK hide #-}@@ -14,7 +17,9 @@ import qualified Data.HashMap.Mutable.Linear as Linear import Data.Monoid.Linear import Data.Unrestricted.Linear+import GHC.TypeLits (ErrorMessage (..)) import qualified Prelude.Linear as Linear hiding (insert)+import Prelude.Linear.Unsatisfiable (Unsatisfiable, unsatisfiable) import Prelude (Bool, Int) import qualified Prelude @@ -70,8 +75,11 @@ -- # Typeclass Instances ------------------------------------------------------------------------------- -instance Prelude.Semigroup (Set a) where-  (<>) = Prelude.error "Prelude.(<>): invariant violation, unrestricted Set"+instance+  (Unsatisfiable ('Text "Using Prelude's Semigroup methods on a Data.Set.Mutable.Linear is vacuous as there can't be an unrestricted such Set")) =>+  Prelude.Semigroup (Set a)+  where+  (<>) = unsatisfiable  instance (Keyed a) => Semigroup (Set a) where   (<>) = union
src/Data/Unrestricted/Linear/Internal/Instances.hs view
@@ -21,10 +21,13 @@ -- other classes (for cleanness) in this module to avoid this dependence. module Data.Unrestricted.Linear.Internal.Instances where +import Data.ByteString (ByteString)+import Data.ByteString.Short (ShortByteString) import qualified Data.Functor.Linear.Internal.Applicative as Data import qualified Data.Functor.Linear.Internal.Functor as Data import Data.Monoid.Linear import Data.Replicator.Linear.Internal.Instances ()+import qualified Data.Text import Data.Unrestricted.Linear.Internal.Consumable import Data.Unrestricted.Linear.Internal.Dupable import Data.Unrestricted.Linear.Internal.Movable@@ -189,6 +192,27 @@     V       . Unsafe.toLinear (Vector.fromListN (V.theLength @n))       Data.<$> dupR (Unsafe.toLinear Vector.toList xs)++instance Movable ByteString where+  move = Unsafe.toLinear $ \s -> s `seq` Ur s++deriving via (AsMovable ByteString) instance Consumable ByteString++deriving via (AsMovable ByteString) instance Dupable ByteString++instance Movable ShortByteString where+  move = Unsafe.toLinear $ \s -> s `seq` Ur s++deriving via (AsMovable ShortByteString) instance Consumable ShortByteString++deriving via (AsMovable ShortByteString) instance Dupable ShortByteString++instance Movable Data.Text.Text where+  move = Unsafe.toLinear $ \s -> s `seq` Ur s++deriving via (AsMovable Data.Text.Text) instance Consumable Data.Text.Text++deriving via (AsMovable Data.Text.Text) instance Dupable Data.Text.Text  -- Some stock instances