Permutations with repetitions: Difference between revisions

→‎Applescript lazy evaluation: Switched to generator, updated output & primitives
(→‎Applescript lazy evaluation: Switched to generator, updated output & primitives)
Line 154:
===Partial evaluation===
Permutations with repetition by treating the <math>n^k</math> elements as an ordered set, and writing a function from a zero-based index to the nth permutation. This allows us terminate a repeated generation on some condition, or explore a sub-set without needing to generate the whole set:
<lang AppleScript>use AppleScript version "2.4"
<lang AppleScript>-- Nth PERMUTATION WITH REPETITION -------------------------------------------
use framework "Foundation"
use scripting additions
 
-- permutesWithRepns :: [a] -> Int -> Generator [[a]]
on permutesWithRepns(xs, n)
script
property f : curry3(my nthPermutationWithRepn)'s |λ|(xs)'s |λ|(n)
property limit : (length of xs) ^ n
property i : -1
on |λ|()
set i to i + 1
if i < limit then
return f's |λ|(i)
else
missing value
end if
end |λ|
end script
end permutesWithRepns
 
 
-- nthPermutationWithRepn :: [a] -> Int -> Int -> [a]
on nthPermutationWithRepn(xs, groupSizeintGroup, iIndexintIndex)
set intBase to length of xs
setif intSetSizeintIndex to< (intBase ^ groupSizeintGroup) then
set ds to baseDigits(intBase, xs, intIndex)
if intBase < 1 or iIndex > intSetSize then
{}
else
set baseElems to inBaseElements(xs, iIndex)
set intZeros to groupSize - (length of baseElems)
if-- intZerosWith >any 0'leading thenzeros' required by length
replicate(intGroup - (length of replicate(intZerosds), item 1 of xs) & baseElemsds
else
missing baseElemsvalue
end if
end if
end nthPermutationWithRepn
 
 
-- inBaseElements :: [a] -> Int -> [String]
-- baseDigits :: Int -> [a] -> [a]
on inBaseElements(xs, n)
on set baseDigits(intBase, to length ofdigits, xsn)
script
script nextDigit on |λ|(v)
on |λ|(residue) if 0 = v then
set {divided, remainder} to quotRemNothing(residue, intBase)
else
{valid:divided > 0, value: Just(Tuple(item (remainder1 + 1(v mod intBase)) of xs)digits, new:divided}¬
v div intBase))
end if
end |λ|
end script
unfoldr(result, n)
end baseDigits
reverse of unfoldr(nextDigit, n)
end inBaseElements
 
 
-- TEST ----------------------------------------------------------------------
on run
set cs to "ACKR"
script
set wordLength to on |λ|(x)5
set gen to permutesWithRepns(cs, wordLength)
nthPermutationWithRepn({"X", "Y", "Z"}, 4, x)
end |λ|
end script
--set 30thi to 35th members of the series0
set v to gen's |λ|() -- First permutation drawn from series
map(result, enumFromTo(30, 35))
set alpha to v
set psi to alpha
repeat while missing value is not v
set s to concat(v)
if "crack" = toLower(s) then
return ("Permutation " & (i as text) & " of " & ¬
(((length of cs) ^ wordLength) as integer) as text) & ¬
": " & s & linefeed & ¬
"Found after searching from " & alpha & " thru " & psi
else
set i to 1 + i
set psi to v
end if
set v to gen's |λ|()
end repeat
end run
 
 
-- GENERIC FUNCTIONS ----------------------------------------------------------
 
-- enumFromToJust :: Inta -> IntMaybe -> [Int]a
on enumFromToJust(m, nx)
{type:"Maybe", Nothing:false, Just:x}
if m > n then
end Just
set d to -1
 
-- Nothing :: Maybe a
on Nothing()
{type:"Maybe", Nothing:true}
end Nothing
 
-- Tuple (,) :: a -> b -> (a, b)
on Tuple(a, b)
{type:"Tuple", |1|:a, |2|:b, length:2}
end Tuple
 
-- concat :: [[a]] -> [a]
-- concat :: [String] -> String
on concat(xs)
set lng to length of xs
if 0 < lng and string is class of (item 1 of xs) then
set acc to ""
else
set dacc to 1{}
end if
setrepeat lstwith i from 1 to {}lng
repeat with i from mset acc to nacc & item i byof dxs
set end of lst to i
end repeat
return lstacc
end enumFromToconcat
 
-- mapcurry3 :: ((a, b, c) -> bd) -> [a] -> [b] -> c -> d
on mapcurry3(f, xs)
tell mReturn(f)script
seton lng to length of xs|λ|(a)
set lst to {} script
repeat with i from 1 to lng on |λ|(b)
set end of lst to |λ|(item i of xs, i, xs)script
end repeat on |λ|(c)
|λ|(a, b, c) of mReturn(f)
return lst
end tell|λ|
end script
end map
end |λ|
end script
end |λ|
end script
end curry3
 
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: HandlerFirst-class m => (a -> b) -> m (a -> Scriptb)
on mReturn(f)
if class of f is script then
Line 244 ⟶ 294:
end mReturn
 
-- Egyptian multiplication - progressively doubling a list, appending
-- quotRem :: Integral a => a -> a -> (a, a)
-- stages of doubling to an accumulator where needed for binary
on quotRem(m, n)
-- assembly of a target length
{m div n, m mod n}
end quotRem
 
-- replicate :: Int -> a -> [a]
on replicate(n, a)
Line 263 ⟶ 311:
end replicate
 
-- take :: Int -> [a] -> [a]
-- take :: Int -> String -> String
on take(n, xs)
set c to class of xs
if list is c then
if 0 < n then
items 1 thru min(n, length of xs) of xs
else
{}
end if
else if string is c then
if 0 < n then
text 1 thru min(n, length of xs) of xs
else
""
end if
else if script is c then
set ys to {}
repeat with i from 1 to n
set end of ys to xs's |λ|()
end repeat
return ys
else
missing value
end if
end take
 
-- toLower :: String -> String
on toLower(str)
set ca to current application
((ca's NSString's stringWithString:(str))'s ¬
lowercaseStringWithLocale:(ca's NSLocale's currentLocale())) as text
end toLower
 
-- > unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10
-- > [10,9,8,7,6,5,4,3,2,1]
-- unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
on unfoldr(f, v)
set mfxr to mReturnTuple(fv, v) -- (value, remainder)
set lstxs to {}
set recM to mf's |λ|(v)
repeat while (valid of recM) is true
set end of lst to value of recM
set recM to mf's |λ|(new of recM)
end repeat
lst & value of recM
end unfoldr
 
-- until :: (a -> Bool) -> (a -> a) -> a -> a
on |until|(p, f, x)
set mp to mReturn(p)
set v to x
tell mReturn(f)
repeat until-- mp'sFunction |λ|(v)applied to remainder.
set vmb to |λ|(v|2| of xr)
if Nothing of mb then
exit repeat
else -- New (value, remainder) tuple,
set xr to Just of mb
-- and value appended to output list.
set end of xs to |1| of xr
end if
end repeat
end tell
return vxs
end |until|unfoldr</lang>
{{Out}}
<pre>Permutation 589 of 1024: CRACK
<lang AppleScript>{{"Y", "X", "Y", "X"}, {"Y", "X", "Y", "Y"}, {"Y", "X", "Y", "Z"},
Found after searching from AAAAA thru ARACK</pre>
{"Y", "X", "Z", "X"}, {"Y", "X", "Z", "Y"}, {"Y", "X", "Z", "Z"}}</lang>
 
=={{header|ALGOL 68}}==
9,655

edits