# 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 errorwork outside of Python? – Dennis – 2014-10-10T18:15:32.063@BetaDecay - So CJam's

`,`

is allowed ? which works like`10 ,`

=`[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]`

and`range(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