AppleScript, 382
AppleScript is fun to golf but can't compete with other languages. I count the function bodies, but not the declarations of on handler(arg)
and end handler
.
--range: 82 bytes
on r(i,j,c)
try
set a to{}
repeat while i/c<j/c
set a to a&i
set i to i+c
end
a
on error
1
end
end r
-- type: 131 bytes
on type(x)
try
if x=x as list
"list"
else if x=x as text
"str"
else if x=x as real and"."is in x as text
"float"
else
"int"
end
on error
1
end
end type
-- round: 70 bytes
on round2(x,p)
try
set m to 10^-p
if x<0then set m to-m
(x+m/2)div m*m
on error
1
end
end round2
-- enumerate: 99 bytes
on enumerate(x)
try
set a to{}
repeat with i in r(1,1+count x,1)
set a to a&{{i-1,x's item i}}
end
a
on error
1
end
end enumerate
-- examples: see results in event log
log r(1, 10, 1)
log r(1, 10, 2)
log r(10, 5, -1)
log type(12)
log type(12.0)
log type("12")
log type({13, 45})
log round2(0.5, 0)
log round2(0.2, 0)
log round2(3.14159, 3)
log round2(127.56, -2)
log round2(12.564, 2)
log round2(1457, -2)
log enumerate({1, 2, 3, 4})
log enumerate({"spam", "eggs"})
log enumerate(23)
log round2(56, "hello")
log r("hi", 4, 1)
range
I renamed range
to r
because my enumerate
function calls r
.
I use AppleScript errors to detect invalid arguments. If AppleScript raises an error, then the try
structure returns 1. Beware that range([1], "10", 1)
raises TypeError in Python, but r({1}, "10", 1)
is valid here, because AppleScript's operators accept single-item lists and strings as numbers.
The try
body is just this:
set a to {} -- empty list
repeat while i / c < j / c
set a to a & i -- append i to list
set i to i + c
end
The condition needs to be i < j
when c is positive, or i > j
when c is negative. I golfed it as i/c<j/c
, because the division reverses the comparison when c is negative. As a bonus, c being zero raises a division by zero error, so I correctly reject c being zero as invalid.
Beware that set a to a & i
is slow because it copies the whole list a
every time. The fast way might look like set r to a reference to a
, then set end of r to i
, but that is not golf.
type
AppleScript's type operator is class of x
(or x's class
). My own type
function uses operator =
, because 1 + "1"
is 2 but 1 = "1"
is false. The try
body is this:
if x = (x as list)
"list"
else if x = (x as text)
"str"
else if x = (x as real) and "." is in (x as text)
"float"
else -- assume x = (x as integer)
"int"
end
Some arguments are invalid; try calling type(AppleScript)
or type(type)
. Then x as text
or x as real
raises an error and I return 1. It helps that x as list
always works and x as text
works with any number.
Because 12 = 12.0
is true, I need another way to tell floats from ints. I observe that 12 as text
is "12" but 12.0 as text
is "12.0", so I check for "." in string. I have no check for infinities or NaN because trying to compute those would raise errors.
round
I renamed round
to round2
because AppleScript has round
in its standard additions. The try
body is this:
set m to 10^-p
if x < 0 then set m to -m
((x + m / 2) div m) * m
I observe div
truncating toward zero. For rounding, I must calculate x + m / 2
when x is positive, or x - m / 2
when x is negative. For golf, I can negate m. In the div m*m
part, the negative sign of m cancels itself.
Python's round
typically returns a float, but this round2
often returns an integer. AppleScript's operators like to convert floats to integers, perhaps to help 68k Macs with no FPU. (PowerPC Macs emulated a 68LC040 with no FPU.)
enumerate
My enumerate
also works with strings. The try
body is this:
set a to {}
repeat with i in r(1, 1 + (count x), 1)
set a to a & {{i - 1, x's item i}}
end
a
I must not use AppleScript's range loop (repeat with i from 1 to count x
), but I may call my own range function. I tried to golf away the final a, but I need it when enumerating the empty list or string.
Beware that i is a reference to a number, not the number itself. If I looped in r(0,count x,1)
and collected {{i,x's item(i+1)}}
, the result might look like {{item 1 of {0, 1}, "spam"}, {item 2 of {0, 1}, "eggs"}}
. The operations i-1
and x's item i
coerce i to a number.
The "return 1" imposition generate a ugly bug, because it is possible to confuse one right answer as round(0.5,0) with one not right as round("hi",0) (both one would return 1). For the remain it was a little difficult find the right extreme for range(). In total it is a very good question: Thank you – RosLuP – 2017-11-13T04:30:46.273
Use
lambda
for 0 bytes? (The entire statement is declaring a function) – pppery – 2019-10-18T20:18:09.6134
I'm voting to close this question as off-topic because it a multi-part challenge with no interaction between the parts
– pppery – 2019-11-14T04:20:57.1701How should throw a type error work outside of Python? – Dennis – 2014-10-10T18:15:32.063
@BetaDecay - So CJam's
,
is allowed ? which works like10 ,
=[0 1 2 3 4 5 6 7 8 9]
? – Optimizer – 2014-10-10T18:36:57.983@Optimizer I'm afraid not – Beta Decay – 2014-10-10T18:57:13.960
Does the
range
version have to work for fewer arguments? For example,range(5)
yields[0,1,2,3,4]
andrange(2,5)
yields[2,3,4]
. – Wrzlprmft – 2014-10-12T20:08:46.427@Wrzlprmft No, to be fair on other languages, it must use three arguments – Beta Decay – 2014-10-12T20:09:22.430
So, I may not even write a version of
range
which is capable of dealing with fewer arguments, if I want to? – Wrzlprmft – 2014-10-12T20:11:35.720@Wrzlprmft Well... Go on then – Beta Decay – 2014-10-12T20:12:21.730
Are you sure about having
1
returned for invalid arguments? Most solutions do not seem to comply with this. – Wrzlprmft – 2014-10-12T22:52:15.210