Jam don't add like that
APL, 44 bytes
{1=≡⍺⍵:⍺+⍵⋄=/∆←|≡¨⍺⍵:⊃∇¨/↓↑⍺⍵⋄</∆:⍺∘∇¨⍵⋄⍵∇⍺}
APL's +
distributes over arrays as well, but in a different enough manner that this can't really be used. However, there is a built-in depth function (≡
).
Explanation:
1=≡⍺⍵:⍺+⍵
: if the depths of⍺
⍵
are both zero (and therefore the depth of⍺ ⍵
is 1), add them.∆←|≡¨⍺⍵
: take the absolute of the depth of both⍺
and⍵
and store them in∆
. (≡
gives a negative value if not all elements have the same depth.)=/∆
: if they have the same depth:↓↑⍺⍵
: pad the shortest array with zeroes to match the longer array⊃∇¨/
: distribute the function over both arrays
</∆
: if the depth of⍺
is less than that of⍵
:⍺∘∇¨⍵
: bind⍺
and then map over⍵
⍵∇⍺
: if nothing else (so⍵
is deeper than⍺
), swap the arguments and try again.
Mathematica, 122 bytes
d=Depth
x_~f~y_/;d@x>d@y:=y~f~x
x_~f~y_/;d@x<d@y:=x~f~#&/@y
x_List~f~y_:=MapThread[f,{x,y}~PadRight~Automatic]
x_~f~y_=x+y
Defines a recursive function f
which computes the sum. Making use of Mathematica's pattern matching, this function is made up of four separate definitions:
x_~f~y_/;d@x>d@y:=y~f~x
If the depth of x
is greater than that of y
, swap the arguments so that we only have to handle distribution in one direction (which we can do, since addition is commutative).
x_~f~y_/;d@x<d@y:=x~f~#&/@y
If the depth of x
is less thann that of y
, replace each value #
in y
with f[x,#]
, which takes care of the distribution for arguments of unequal depth.
x_List~f~y_:=MapThread[f,{x,y}~PadRight~Automatic]
Otherwise, if one argument is a list (which implies that the other also is a list, since we know they have the same depth), we put both arguments in a list, pad them to the same length with PadRight[..., Automatic]
(which simply fills up a ragged array with zeros to make it rectangular), and then use MapThread
to apply f
to corresponding pairs from the two lists.
And finally, the base case:
x_~f~y_=x+y
If none of the other patterns match, we must be trying to add two numbers, so we just do that.
Haskell, 150 bytes
data L=S Int|V{v::[L]}
d(V z)=1+maximum(d<$>S 0:z);d _=0
S x!S y=S$x+y
x!y|d x<d y=V$(x!)<$>v y|d x>d y=y!x|1<2=V$v x#v y
(x:a)#(y:b)=x!y:a#b;a#b=a++b
Explanation
The first line defines an algebraic data type L
, which is either a S
calar (containing an Int
) or a V
ector (containing a list of L
s, accessed using a record getter v
, which is a partial function L → [L]
.)
The second line defines the depth function: the depth of a V
ector is one plus its maximum depth. I prepend S 0
to the values in the vector, so that depth [] == 1 + maximum [depth (S 0)] == 1
. The depth of “anything else” (a scalar) is 0
.
The third line defines the base case for !
(the addition function): the sum of scalars is simply a scalar.
The fifth line defines a variant of zipWith (!)
that just picks elements from the longest list when one of them is empty.
The fourth line is split in three cases:
x!y | d x<d y = V$(x!)<$>v y
| d x>d y = y!x
| True = V$v x#v y
If the depth of
x
is strictly less than the depth ofy
, map(x!)
over the elements ofy
. (The use ofv
is guaranteed to be valid, asd(y) ≥ 1
.)If the depth of
x
is strictly greater, flip the arguments and restart.If their depths are equal, zip the arguments together with
(!)
. (The use ofv
is guaranteed to be valid, as the cased(x) = d(y) = 0
was handled as a base case.)
Test cases
instance Show L where
show (S x) = show x
show (V x) = show x
lArg = V [S 1, V [S 2, V [S 3, V [S 4]]]]
rArg = V [S 10, V [S 20]]
Then show (lArg ! rArg) == "[[11,[21]],[[12,[22]],[13,[24]]]]"
.