1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
------------------------------------------------------------------------------
-- Library with operations to encapsulate search, i.e., to return all or
-- some values of an expression containing non-deterministic computations
-- in a data strcuture, as I/O operations in order to make the results
-- dependend on the external world, e.g., the schedule for non-determinism.
--
-- To encapsulate search in non-I/O computations, one can use
-- set functions (see module `Control.Search.SetFunctions`).
--
-- Author : Michael Hanus
-- Version: October 2026
------------------------------------------------------------------------------

module Control.Search.AllValues
  ( getAllValues, getAllValuesDFS, getOneValue, getOneValueDFS, getAllFailures )
 where

import Control.Search.Unsafe

------------------------------------------------------------------------------

-- | Gets all values of an expression (similarly to Prolog's `findall`).
-- Conceptually, the value is computed on a copy of the expression,
-- i.e., the evaluation of the expression does not share any results.
--
-- The strategy to search for all values depends on the Curry system:
--
-- * PAKCS uses a depth-first search strategy and computes all values at once,
-- * KiCS2 uses a breadth-first search strategy and computes all values lazily.
-- * KMCC uses a fair search strategy and computes all values lazily.
-- * Curry2Go uses a fair search strategy and computes all values lazily.
--
--   In PAKCS, the evaluation suspends as long as the expression
--   or its computed value contain unbound variables.
getAllValues :: a -> IO [a]
getAllValues e = return (allValues e)

-- | Gets all values of an expression.
-- This operation is similar to 'getAllValues' but uses a depth-first search
-- strategy (if available).
-- Thus, it could be more efficient than 'getAllValues' but it might
-- not terminate (instead of computing of all values) if the search space
-- is infinite.
getAllValuesDFS :: a -> IO [a]
getAllValuesDFS e = return (allValuesDFS e)

-- | Gets one value of an expression or `Nothing`
-- if the expression has no value.
-- Conceptually, the value is computed on a copy of the expression,
-- i.e., the evaluation of the expression does not share any results.
--
-- The strategy to search for a value depends on the Curry system:
--
-- * PAKCS uses a depth-first search strategy,
-- * KiCS2 uses a breadth-first search strategy, and
-- * KMCC uses a fair search strategy.
-- * Curry2Go uses a fair search strategy.
--
-- In PAKCS, the evaluation suspends as long as the expression
-- or its computed value contain unbound variables.
getOneValue :: a -> IO (Maybe a)
getOneValue x = return (oneValue x)

-- | Gets one value of an expression or `Nothing`
-- if the expression has no value.
-- This operation is similar to 'getOneValue' but uses a depth-first search
-- strategy (if available).
-- Thus, it could be more efficient than 'getOneValue' but it might not terminate
-- (instead of computing of value) if the search space is infinite.
getOneValueDFS :: a -> IO (Maybe a)
getOneValueDFS x = return (oneValueDFS x)

-- | Returns a list of values that do not satisfy a given constraint.
-- As a simple example, the expression
--
--     getAllFailures ([] ? [1] ? [2]) (\xs -> head xs =:= 1)
--
-- evaluates to `[[], [2]]`.
getAllFailures :: a           -- ^ an expression ´e´ (e.g., a generator
                              --   evaluable to various values)
               -> (a -> Bool) -- ^ a constraint ´c´ that should not be satisfied
               -> IO [a]      -- ^ list of all values of `e`
                              --   such that `(c e)` is not provable
getAllFailures generator test = do
  xs <- getAllValues generator
  failures <- mapM (naf test) xs
  return $ concat failures

-- (naf c x) returns [x] if (c x) fails, and [] otherwise.
naf :: (a -> Bool) -> a -> IO [a]
naf c x = getOneValue (c x) >>= return . maybe [x] (const [])

------------------------------------------------------------------------------