-
Notifications
You must be signed in to change notification settings - Fork 0
/
LiComboP.icn
126 lines (121 loc) · 5.25 KB
/
LiComboP.icn
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
$ifndef _LiComboP_
$define _LiComboP_
############################################################################
#
# File: LiComboP.icn
#
# Subject: Procedures to suspend lists combining sequences.
#
# Author: Arthur C. Eschenlauer
#
# Date: September 30, 2021
#
############################################################################
#
# This file is in the public domain.
#
# SPDX-License-Identifier: CC-PDDC
# https://spdx.org/licenses/CC-PDDC.html
#
############################################################################
#
# required include: wora.icn for wora(id)
#
############################################################################
#
# procedure LiP(A)
# Suspend lists combining infinite sequences.
# LiP uses wora(LiP) to determine whether to use LiFiniteP (the
# default) or nAltP to combine memoized results.
#
# procedure LiFiniteP(LofC)
# Recursively suspend lists combining finite seqs.
#
# procedure nAltP(LofC)
# Recurrently suspend lists combining finite seqs.
#
############################################################################
$ifndef _wora_
$include "wora.icn"
$endif # _wora_
procedure LiP(A) #: produce lists combining infinite sequences
# Generate combinations of argument results for list-invocation,
# not requiring that the arguments yield finite sequences:
# - For each co-expression, create an empty memoization list to hold
# the results that it will produce.
# - Activate each co-expression, putting the result onto its list.
# - Next produce the combination of the (one-member) memoization lists.
# - Next, in round-robin fashion:
# - activate each co-expression;
# - if activation succeeded:
# - add the result to its memoization list
# - and then produce the combinations of that result with the
# previous results of the other co-expressions, i.e., with
# all of the members of their memoization lists.
local done # set to not &null when all C are exhausted
local i # current C index, element of 1 to nA
local j # reusable index, element of 1 to nA
local lcpCL # list of C to be passed to LiFiniteP
local memoLL # list of memoization lists
local nA # size of A
local saveL # temporary holder to save memoLL[i]
local fingen # generates lists of combinations of finite sequences
nA := *A; memoLL := [] # Initialization
fingen := \wora(LiP) | LiFiniteP # Set fingen from wora(LiP)|default
every i := 1 to nA # Collect first result from each C,
do put( memoLL, [@A[i]] ) | fail # which is strictly required.
until \done # Repeat until every C is exhausted
do {
done := 1 # Revert to &null when @C succeeds
every i := 1 to nA # For any @(!A) that succeeds,
do { # memoize the result and suspend L
saveL := ( # If @A[i] fails, advance to i + 1
(/saveL, memoLL[1]) | # - first activation, special case
put( memoLL[i], @A[i] ) | # - otherwise, require activation
next # - or next i
)[-1:0] # saveL slice has only last value
done := &null # C produces a value
saveL :=: memoLL[i] # Save memoization list for i
lcpCL := [] # Build list of C, each produ-
every j := 1 to nA # cing the memoized values
do put(lcpCL, create !memoLL[j]) # but with only latest @A[i]
suspend fingen(lcpCL) # Suspend combinations from memoization lists
memoLL[i] :=: saveL # Revert memoization list for i
} # next i
} # fail once every C is exhausted
end
procedure LiFiniteP(LofC) #: recursively suspend lists combining finite seqs
# For a list of co-expressions that produce a finite sequence
# of results; produce a list of each combination of results.
# This "recursive suspension" technique was adapted from
# Bob Alexander's regexp.icn from the IPL.
# For example, LiFiniteP{1 to 2, 5 to 6} produces:
# [1,5], then [1,6], then [2,5], and then [2,6].
local C, v
# For the first C to be activated more than once,
# all but the first C must be finite.
C := ^LofC[1]
while v := @C
do if *LofC > 1
then suspend [v] ||| LiFiniteP(LofC[2:0])
else suspend [v]
end
procedure nAltP(A) #: recurrently suspend lists combining finite seqs
# Steve Wampler's recurrent solution, comparable in speed to
# Bob Alexander's solution
local i # Current co-expression to evaluate
local solution # List of co-expression values
i := 1 ; solution := list(*A)
repeat {
while solution[i] := @A[i] do {
if (i +:= 1) > *A
then { # Finished with this solution list
suspend solution
i -:= 1 # "backtrack"...
}
}
A[i] := ^A[i] # Prepare for re-entry on l-to-r eval.
if (i -:= 1) = 0 then fail # "backtrack" or fail if all done
}
end
$endif # _LiComboP_