Skip to content

Commit

Permalink
Merge pull request #4 from bruderj15/main
Browse files Browse the repository at this point in the history
Publish v0.1.2
  • Loading branch information
bruderj15 authored Nov 29, 2024
2 parents 678ea71 + 81a6f75 commit a22f327
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 11 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [PVP versioning](https://pvp.haskell.org/).

## v0.1.2 _(2024-11-29)_

### Added
- Added type aliases `SomesF` and `SomeF` for existentials with fixed containers
- Added `mapSome` with infix `(<~$>)` and `traverseSome` with infix `(<~*>)`

## v0.1.1 _(2024-11-29)_

### Added
Expand Down
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,25 @@ It allows you to enforce multiple constraints on polymorphic types and container

## Core

- **Existential Types**: `Somes` and `Somes1` provide existential wrappers for types with multiple constraints.
- **Convenient Aliases**: Simplified types `Some` and `Some1` for scenarios where just one constraint is needed.

- **Existential types**: `Somes` and `Somes1` provide existential wrappers for types with multiple constraints.
- **Convenient aliases**: Simplified types `Some` and `Some1` for scenarios where just one constraint is needed.
- **More convenient aliases**: Simplified types `SomeF` and `SomesF` for scenarios where the container of a `Somes1` is known.
- **Natural transformations with constraints**
- `mapSome :: (forall a. AllC csa a => f a -> g a) -> SomesF f csa -> SomesF g csa`
- `traverseSome :: Functor m => (forall a. AllC csa a => f a -> m (g a)) -> SomesF f csa -> m (SomesF g csa)`
## Usage

```haskell
import Data.Some.Constraint

someShowableOrd :: Somes '[Show, Ord]
someShowableOrd = Some (mempty :: [Double])
someShowableOrd = Some [1, 2, 3 :: Int]

someNumFunctor :: Some1 Functor Num
someNumFunctor = Some1 $ [1, 2, 3 :: Int]
someNumFunctor = Some1 [1, 2, 3 :: Int]

someListShowable :: SomeF [] Show
someListShowable = Some1 [1, 2, 3 :: Int]
```

## Contact information
Expand Down
2 changes: 1 addition & 1 deletion constrained-some.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 3.0
name: constrained-some
version: 0.1.1
version: 0.1.2
synopsis: Existential type that can be constrained
description: This library provides utilities for working with existential types and type-level constraints.
It allows you to enforce multiple constraints on polymorphic types and containers complementing the package some.
Expand Down
59 changes: 54 additions & 5 deletions src/Data/Some/Constraint.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,27 @@
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE QuantifiedConstraints #-}

module Data.Some.Constraint where
module Data.Some.Constraint
(
-- * Combining constraints
AllC

-- * Existentials
-- ** Flat existentials
, Somes(..), Some

-- ** Containerized existentials
-- *** Constrained containers
, Somes1(..), Some1

-- *** Fixed containers
, SomesF, SomeF
, mapSome, (<~$>)
, traverseSome, (<~*>)
) where

import Data.Kind

Expand All @@ -34,6 +53,12 @@ data Somes cs where
(a :: Type).
AllC cs a => a -> Somes cs

instance {-# OVERLAPPING #-} Show (Somes (Show ': cs)) where
showsPrec d (Some x) = showParen (d > 10) $ showString "Some " . showsPrec 11 x

instance {-# OVERLAPPABLE #-} Show (Somes cs) => Show (Somes (c ': cs)) where
showsPrec d (Some x) = showsPrec d (Some @cs x)

-- | Alias for 'Somes' with just one 'Constraint'.
type Some c = Somes '[c]

Expand All @@ -57,8 +82,32 @@ data Somes1 csf csa where
-- | Alias for 'Somes1' with just one 'Constraint'.
type Some1 cf ca = Somes1 '[cf] '[ca]

instance {-# OVERLAPPING #-} Show (Somes (Show ': cs)) where
showsPrec d (Some x) = showParen (d > 10) $ showString "Some " . showsPrec 11 x
-- | Alias for 'Somes1' with a container @f@ and multiple 'Constraint's @csa@ for its elements.
type SomesF f csa = Somes1 '[(~) f] csa

instance {-# OVERLAPPABLE #-} Show (Somes cs) => Show (Somes (c ': cs)) where
showsPrec d (Some x) = showsPrec d (Some @cs x)
-- | Alias for 'SomeF' with just one 'Constraint' for its elements.
type SomeF f c = SomesF f '[c]

-- | Natural transformation of one container to another.
mapSome :: (forall a. AllC csa a => f a -> g a) -> SomesF f csa -> SomesF g csa
mapSome f (Some1 x) = Some1 (f x)

infixl 4 <~$>
-- | Infix version of 'mapSome'.
(<~$>) :: (forall a. AllC csa a => f a -> g a) -> SomesF f csa -> SomesF g csa
(<~$>) = mapSome

-- | Natural transformation of one container to another - with side effects in @m@.
traverseSome :: Functor m => (forall a. AllC csa a => f a -> m (g a)) -> SomesF f csa -> m (SomesF g csa)
traverseSome f (Some1 x) = Some1 <$> f x

infixl 4 <~*>
-- | Infix version of 'traverseSome'.
(<~*>) :: Functor m => (forall a. AllC csa a => f a -> m (g a)) -> SomesF f csa -> m (SomesF g csa)
(<~*>) = traverseSome

instance {-# OVERLAPPING #-} (forall a. Show a => Show (f a)) => Show (SomesF f (Show ': cs)) where
showsPrec d (Some1 x) = showParen (d > 10) $ showString "Some " . showsPrec 11 x

instance {-# OVERLAPPABLE #-} Show (SomesF f cs) => Show (SomesF f (c ': cs)) where
showsPrec d (Some1 x) = showsPrec d (Some1 @_ @('[(~) f]) @cs x)

0 comments on commit a22f327

Please sign in to comment.