Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .hlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1558,6 +1558,12 @@
name: "Use 'bool' from Relude"
note: "'bool' is already exported from Relude"
rhs: bool
- warn:
lhs: "(\\a -> f a && g a)"
rhs: "f .&& g"
- warn:
lhs: "(\\a -> f a || g a)"
rhs: "f .|| g"
- warn:
lhs: Data.Hashable.Hashable
name: "Use 'Hashable' from Relude"
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ The changelog is available [on GitHub][2].
## Unreleased

- Allow containers-0.8.
- Add predicate combinators

## 1.2.2.0 – Oct 13, 2024

Expand Down
2 changes: 2 additions & 0 deletions hlint/hlint.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,8 @@ in [ Rule.Arguments { arguments =
, warnReexport "unless" "Control.Monad"
, warnReexport "when" "Control.Monad"
, warnReexport "bool" "Data.Bool"
, warnSimple "(\\a -> f a && g a)" "f .&& g"
, warnSimple "(\\a -> f a || g a)" "f .|| g"

-- Container
, warnReexport "Hashable" "Data.Hashable"
Expand Down
1 change: 1 addition & 0 deletions relude.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ library
Relude.Applicative
Relude.Base
Relude.Bool
Relude.Bool.Extra
Relude.Bool.Guard
Relude.Bool.Reexport
Relude.Container
Expand Down
3 changes: 3 additions & 0 deletions src/Relude/Bool.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ with monads.
module Relude.Bool
( module Relude.Bool.Reexport
-- $reexport
, module Relude.Bool.Extra
-- $reexport
, module Relude.Bool.Guard
-- $guard
) where

import Relude.Bool.Extra
import Relude.Bool.Guard
import Relude.Bool.Reexport

Expand Down
65 changes: 65 additions & 0 deletions src/Relude/Bool/Extra.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{-# LANGUAGE Safe #-}

{- |
Module : Relude.Bool.Extra
Copyright : (c) 2025 drlkf
(c) 2025 Kowainik
SPDX-License-Identifier : MIT
Maintainer : Kowainik <[email protected]>
Stability : Stable
Portability : Portable

Convenient functions to work with predicates.
-}

module Relude.Bool.Extra
( (.&&)
, (.||)
) where

import Relude.Bool.Reexport (Bool, (&&), (||))

{- | Predicate @and@ combinator.

Combine two predicate functions into one with @and@ boolean logic.

>>> even .&& (> 0) $ 2
True

>>> odd .&& (> 0) $ 2
False

>>> even .&& (< 0) $ 2
False

-}
infixr 3 .&&
(.&&)
:: (a -> Bool)
-> (a -> Bool)
-> (a -> Bool)
(.&&) p1 p2 a = p1 a && p2 a
{-# INLINE (.&&) #-}

{- | Predicate @or@ combinator.

Combine two predicate functions into one with @or@ boolean logic.
Lazy in the second argument.

>>> even .|| (> 0) $ 2
True

>>> even .|| (< 0) $ 2
True

>>> even .|| error "impossible" $ 2
False

-}
infixr 2 .||
(.||)
:: (a -> Bool)
-> (a -> Bool)
-> (a -> Bool)
(.||) p1 p2 a = p1 a || p2 a
{-# INLINE (.||) #-}
24 changes: 23 additions & 1 deletion test/Test/Relude/Property.hs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ import Data.List (nub)
import Hedgehog (Group (..), Property, assert, forAll, property, (===))

import Test.Relude.Container.One (oneProps)
import Test.Relude.Gen (genBoolList, genIntList, genUtf8ByteString, genUtf8String, genUtf8Text)
import Test.Relude.Gen (genBoolList, genInt, genIntList, genUtf8ByteString, genUtf8String,
genUtf8Text)


hedgehogTestList :: [Group]
hedgehogTestList =
[ utfProps
, listProps
, logicProps
, predicateOperatorProps
, oneProps
]

Expand Down Expand Up @@ -106,3 +108,23 @@ prop_orM :: Property
prop_orM = property $ do
bs <- forAll genBoolList
orM (pure <$> bs) === pure @Maybe (or bs)

----------------------------------------------------------------------------
-- predicate operators
----------------------------------------------------------------------------

predicateOperatorProps :: Group
predicateOperatorProps = Group "predicate logic operators property tests"
[ (".&&", prop_andP)
, (".||", prop_orP)
]

prop_andP :: Property
prop_andP = property $ do
x <- forAll genInt
(even x && x > 0) === (even .&& (> 0)) x

prop_orP :: Property
prop_orP = property $ do
x <- forAll genInt
(even x || x > 0) === (even .|| (> 0)) x