Sum of first n cubes: Difference between revisions
Content added Content deleted
(→{{header|AppleScript}}: Replaced a map-accumulation with a scanning accumulation.) |
|||
Line 57: | Line 57: | ||
1071225 1168561 1272384 1382976 1500625</pre> |
1071225 1168561 1272384 1382976 1500625</pre> |
||
=={{header|AppleScript}}== |
=={{header|AppleScript}}== |
||
<lang applescript> |
<lang applescript>------------------- SUM OF FIRST N CUBES ----------------- |
||
"use strict"; |
|||
-- sumsOfFirstNCubes :: Int -> [Int] |
|||
// -------------- SUM OF FIRST N CUBES --------------- |
|||
on sumsOfFirstNCubes(n) |
|||
script go |
|||
on |λ|(a, x) |
|||
a + (x ^ 3) as integer |
|||
end |λ| |
|||
end script |
|||
scanl(go, 0, enumFromTo(1, n - 1)) |
|||
end sumsOfFirstNCubes |
|||
// sumsOfFirstNCubes :: Int -> [Int] |
|||
const sumsOfFirstNCubes = n => |
|||
// Cumulative sums of first n cubes. |
|||
scanl( |
|||
a => x => a + (x ** 3) |
|||
)(0)( |
|||
enumFromTo(1)(n - 1) |
|||
); |
|||
--------------------------- TEST ------------------------- |
|||
on run |
|||
table(5, sumsOfFirstNCubes(50)) |
|||
end run |
|||
// ---------------------- TEST ----------------------- |
|||
// main :: IO () |
|||
const main = () => |
|||
table(" ")(justifyRight)( |
|||
chunksOf(5)( |
|||
sumsOfFirstNCubes(50) |
|||
.map(x => `${x}`) |
|||
) |
|||
); |
|||
------------------------- GENERIC ------------------------ |
|||
-- enumFromTo :: Int -> Int -> [Int] |
|||
// --------------------- GENERIC --------------------- |
|||
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 |
|||
lst |
|||
else |
|||
{} |
|||
end if |
|||
end enumFromTo |
|||
// enumFromTo :: Int -> Int -> [Int] |
|||
const enumFromTo = m => |
|||
n => Array.from({ |
|||
length: 1 + n - m |
|||
}, (_, i) => m + i); |
|||
-- scanl :: (b -> a -> b) -> b -> [a] -> [b] |
|||
on scanl(f, startValue, xs) |
|||
tell mReturn(f) |
|||
set v to startValue |
|||
set lng to length of xs |
|||
set lst to {startValue} |
|||
repeat with i from 1 to lng |
|||
set v to |λ|(v, item i of xs, i, xs) |
|||
set end of lst to v |
|||
end repeat |
|||
return lst |
|||
end tell |
|||
end scanl |
|||
// scanl :: (b -> a -> b) -> b -> [a] -> [b] |
|||
const scanl = f => startValue => xs => |
|||
// The series of interim values arising |
|||
// from a catamorphism. Parallel to foldl. |
|||
xs.reduce((a, x) => { |
|||
const v = f(a[0])(x); |
|||
-- mReturn :: First-class m => (a -> b) -> m (a -> b) |
|||
return [v, a[1].concat(v)]; |
|||
on mReturn(f) |
|||
}, [startValue, [startValue]])[1]; |
|||
-- 2nd class handler function lifted into 1st class script wrapper. |
|||
if script is class of f then |
|||
f |
|||
else |
|||
script |
|||
property |λ| : f |
|||
end script |
|||
end if |
|||
end mReturn |
|||
------------------------ FORMATTING ---------------------- |
|||
-- table :: Int -> [String] -> String |
|||
on table(n, xs) |
|||
const chunksOf = n => { |
|||
-- A list of strings formatted as |
|||
// xs split into sublists of length n. |
|||
-- right-justified rows of n columns. |
|||
// The last sublist will be short if n |
|||
set vs to map(my str, xs) |
|||
// does not evenly divide the length of xs . |
|||
set w to length of last item of vs |
|||
unlines(map(my unwords, ¬ |
|||
const chunk = xs.slice(0, n); |
|||
chunksOf(n, map(justifyRight(w, space), vs)))) |
|||
end table |
|||
return 0 < chunk.length ? ( |
|||
[chunk].concat( |
|||
go(xs.slice(n)) |
|||
) |
|||
) : []; |
|||
}; |
|||
-- chunksOf :: Int -> [a] -> [[a]] |
|||
return go; |
|||
on chunksOf(k, xs) |
|||
}; |
|||
script |
|||
on go(ys) |
|||
set ab to splitAt(k, ys) |
|||
set a to item 1 of ab |
|||
if {} ≠ a then |
|||
{a} & go(item 2 of ab) |
|||
else |
|||
a |
|||
end if |
|||
end go |
|||
end script |
|||
result's go(xs) |
|||
end chunksOf |
|||
-- justifyRight :: Int -> Char -> String -> String |
|||
on justifyRight(n, cFiller) |
|||
const compose = (...fs) => |
|||
script |
|||
// A function defined by the right-to-left |
|||
on |λ|(txt) |
|||
// composition of all the functions in fs. |
|||
if n > length of txt then |
|||
text -n thru -1 of ((replicate(n, cFiller) as text) & txt) |
|||
else |
|||
txt |
|||
end if |
|||
end |λ| |
|||
end script |
|||
end justifyRight |
|||
-- map :: (a -> b) -> [a] -> [b] |
|||
on map(f, xs) |
|||
const flip = op => |
|||
-- The list obtained by applying f |
|||
// The binary function op with |
|||
-- to each element of xs. |
|||
tell mReturn(f) |
|||
1 < op.length ? ( |
|||
set lng to length of xs |
|||
set lst to {} |
|||
repeat with i from 1 to lng |
|||
set end of lst to |λ|(item i of xs, i, xs) |
|||
end repeat |
|||
return lst |
|||
end tell |
|||
end map |
|||
-- Egyptian multiplication - progressively doubling a list, appending |
|||
// intercalate :: String -> [String] -> String |
|||
-- stages of doubling to an accumulator where needed for binary |
|||
const intercalate = s => |
|||
-- assembly of a target length |
|||
// The concatenation of xs |
|||
-- replicate :: Int -> String -> String |
|||
// interspersed with copies of s. |
|||
on replicate(n, s) |
|||
xs => xs.join(s); |
|||
-- Egyptian multiplication - progressively doubling a list, |
|||
-- appending stages of doubling to an accumulator where needed |
|||
-- for binary assembly of a target length |
|||
script p |
|||
on |λ|({n}) |
|||
n ≤ 1 |
|||
end |λ| |
|||
end script |
|||
script f |
|||
on |λ|({n, dbl, out}) |
|||
if (n mod 2) > 0 then |
|||
set d to out & dbl |
|||
else |
|||
set d to out |
|||
end if |
|||
{n div 2, dbl & dbl, d} |
|||
end |λ| |
|||
end script |
|||
set xs to |until|(p, f, {n, s, ""}) |
|||
item 2 of xs & item 3 of xs |
|||
end replicate |
|||
-- splitAt :: Int -> [a] -> ([a], [a]) |
|||
on splitAt(n, xs) |
|||
const justifyRight = n => |
|||
if n > 0 and n < length of xs then |
|||
if class of xs is text then |
|||
{items 1 thru n of xs as text, ¬ |
|||
items (n + 1) thru -1 of xs as text} |
|||
else |
|||
{items 1 thru n of xs, items (n + 1) thru -1 of xs} |
|||
end if |
|||
else |
|||
if n < 1 then |
|||
{{}, xs} |
|||
else |
|||
{xs, {}} |
|||
end if |
|||
end if |
|||
end splitAt |
|||
-- str :: a -> String |
|||
on str(x) |
|||
const maximum = xs => ( |
|||
x as string |
|||
// The largest value in a non-empty list. |
|||
end str |
|||
ys => 0 < ys.length ? ( |
|||
ys.slice(1).reduce( |
|||
(a, y) => y > a ? ( |
|||
y |
|||
) : a, ys[0] |
|||
) |
|||
) : undefined |
|||
)(xs); |
|||
-- unlines :: [String] -> String |
|||
on unlines(xs) |
|||
// (Int -> Char -> String -> String) -> |
|||
-- A single string formed by the intercalation |
|||
// [[String]] -> String |
|||
-- of a list of strings with the newline character. |
|||
const table = gap => |
|||
set {dlm, my text item delimiters} to ¬ |
|||
// A tabulation of rows of string values, |
|||
{my text item delimiters, linefeed} |
|||
set s to xs as text |
|||
// and choice of cell alignment function |
|||
set my text item delimiters to dlm |
|||
// (justifyLeft | center | justifyRight) |
|||
s |
|||
alignment => rows => { |
|||
end unlines |
|||
const |
|||
colWidths = transpose(rows).map( |
|||
row => maximum(row.map(x => x.length)) |
|||
); |
|||
return rows.map( |
|||
compose( |
|||
intercalate(gap), |
|||
zipWith( |
|||
flip(alignment)(" ") |
|||
)(colWidths) |
|||
) |
|||
).join("\n"); |
|||
}; |
|||
-- until :: (a -> Bool) -> (a -> a) -> a -> a |
|||
on |until|(p, f, x) |
|||
set v to x |
|||
set mp to mReturn(p) |
|||
set mf to mReturn(f) |
|||
repeat until mp's |λ|(v) |
|||
set v to mf's |λ|(v) |
|||
end repeat |
|||
v |
|||
end |until| |
|||
// transpose :: [[a]] -> [[a]] |
|||
const transpose = rows => { |
|||
// If any rows are shorter than those that follow, |
|||
// their elements are skipped: |
|||
// > transpose [[10,11],[20],[],[30,31,32]] |
|||
// == [[10,20,30],[11,31],[32]] |
|||
const go = xss => |
|||
0 < xss.length ? (() => { |
|||
const |
|||
h = xss[0], |
|||
t = xss.slice(1); |
|||
-- unwords :: [String] -> String |
|||
return 0 < h.length ? [ |
|||
on unwords(xs) |
|||
[h[0]].concat(t.reduce( |
|||
set {dlm, my text item delimiters} to ¬ |
|||
(a, xs) => a.concat( |
|||
{my text item delimiters, space} |
|||
0 < xs.length ? ( |
|||
set s to xs as text |
|||
[xs[0]] |
|||
set my text item delimiters to dlm |
|||
) : [] |
|||
return s |
|||
), |
|||
end unwords</lang> |
|||
[] |
|||
)) |
|||
].concat(go([h.slice(1)].concat( |
|||
t.map(xs => xs.slice(1)) |
|||
))) : go(t); |
|||
})() : []; |
|||
return go(rows); |
|||
}; |
|||
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] |
|||
const zipWith = f => |
|||
// A list constructed by zipping with a |
|||
// custom function, rather than with the |
|||
// default tuple constructor. |
|||
xs => ys => xs.map( |
|||
(x, i) => f(x)(ys[i]) |
|||
).slice( |
|||
0, Math.min(xs.length, ys.length) |
|||
); |
|||
// MAIN --- |
|||
return main(); |
|||
})();</lang> |
|||
{{Out}} |
{{Out}} |
||
<pre> 0 1 9 36 100 |
<pre> 0 1 9 36 100 |