RosettaCodeData/Task/Recamans-sequence/AppleScript/recamans-sequence.applescript

189 lines
4.6 KiB
AppleScript

use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
on run
-- FIRST FIFTEEN RECAMANs ------------------------------------------------------
script term15
on |λ|(i)
15 = (i as integer)
end |λ|
end script
set strFirst15 to unwords(snd(recamanUpto(true, term15)))
set strFirstMsg to "First 15 Recamans:" & linefeed
display notification strFirstMsg & strFirst15
delay 2
-- FIRST DUPLICATE RECAMAN ----------------------------------------------------
script firstDuplicate
on |λ|(_, seen, rs)
setSize(seen) as integer is not (length of (rs as list))
end |λ|
end script
set strDuplicate to (item -1 of snd(recamanUpto(true, firstDuplicate))) as integer as string
set strDupMsg to "First duplicated Recaman:" & linefeed
display notification strDupMsg & strDuplicate
delay 2
-- NUMBER OF RECAMAN TERMS NEEDED TO GET ALL OF [0..1000]
-- (takes about a minute, depending on system)
set setK to setFromList(enumFromTo(0, 1000))
script supersetK
on |λ|(i, setR)
setK's isSubsetOfSet:(setR)
end |λ|
end script
display notification "Superset size result will take c. 1 min to find ..."
set dteStart to current date
set strSetSize to (fst(recamanUpto(false, supersetK)) - 1) as string
set dteEnd to current date
set strSetSizeMsg to "Number of Recaman terms needed to generate" & ¬
linefeed & "all integers from [0..1000]:" & linefeed
set strElapsed to "(Last result took c. " & (dteEnd - dteStart) & " seconds to find)"
display notification strSetSizeMsg & linefeed & strSetSize
-- CLEARED REFERENCE TO NSMUTABLESET -------------------------------------
set setK to missing value
-- REPORT ----------------------------------------------------------------
unlines({strFirstMsg & strFirst15, "", ¬
strDupMsg & strDuplicate, "", ¬
strSetSizeMsg & strSetSize, "", ¬
strElapsed})
end run
-- nextR :: Set Int -> Int -> Int
on nextR(seen, i, n)
set bk to n - i
if 0 > bk or setMember(bk, seen) then
n + i
else
bk
end if
end nextR
-- recamanUpto :: Bool -> (Int -> Set Int > [Int] -> Bool) -> (Int, [Int])
on recamanUpto(bln, p)
script recaman
property mp : mReturn(p)'s |λ|
on |λ|()
set i to 1
set r to 0
set rs to {r}
set seen to setFromList(rs)
repeat while not mp(i, seen, rs)
set r to nextR(seen, i, r)
setInsert(r, seen)
if bln then set end of rs to r
set i to i + 1
end repeat
set seen to missing value -- clear pointer to NSMutableSet
{i, rs}
end |λ|
end script
recaman's |λ|()
end recamanUpto
-- GENERIC FUNCTIONS -------------------------------------------------------
-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m, n)
if m n then
set lst to {}
repeat with i from m to n
set end of lst to i
end repeat
return lst
else
return {}
end if
end enumFromTo
-- fst :: (a, b) -> a
on fst(tpl)
if class of tpl is record then
|1| of tpl
else
item 1 of tpl
end if
end fst
-- intercalateS :: String -> [String] -> String
on intercalateS(sep, xs)
set {dlm, my text item delimiters} to {my text item delimiters, sep}
set s to xs as text
set my text item delimiters to dlm
return s
end intercalateS
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- NB All names of NSMutableSets should be set to *missing value*
-- before the script exits.
-- ( scpt files containing residual ObjC pointer values can not be saved)
-- setFromList :: Ord a => [a] -> Set a
on setFromList(xs)
set ca to current application
ca's NSMutableSet's ¬
setWithArray:(ca's NSArray's arrayWithArray:(xs))
end setFromList
-- setMember :: Ord a => a -> Set a -> Bool
on setMember(x, objcSet)
missing value is not (objcSet's member:(x))
end setMember
-- setInsert :: Ord a => a -> Set a -> Set a
on setInsert(x, objcSet)
objcSet's addObject:(x)
objcSet
end setInsert
-- setSize :: Set a -> Int
on setSize(objcSet)
objcSet's |count|() as integer
end setSize
-- snd :: (a, b) -> b
on snd(tpl)
if class of tpl is record then
|2| of tpl
else
item 2 of tpl
end if
end snd
-- unlines :: [String] -> String
on unlines(xs)
set {dlm, my text item delimiters} to ¬
{my text item delimiters, linefeed}
set str to xs as text
set my text item delimiters to dlm
str
end unlines
-- unwords :: [String] -> String
on unwords(xs)
intercalateS(space, xs)
end unwords