_elemByElem :: (Num a, Multilinear Tensor a, NFData a)
            => Tensor a                             -- ^ First argument of operator
            -> Tensor a                             -- ^ Second argument of operator
            -> (a -> a -> a)                        -- ^ Operator on tensor elements if indices are different
            -> (Tensor a -> Tensor a -> Tensor a)   -- ^ Tensor operator called if indices are the same
            -> Tensor a                             -- ^ Result tensor
_elemByElem t1 t2 f op = 
    let commonIndices = 
            if indices t1 /= indices t2 then
                Data.List.filter (`Data.List.elem` indicesNames t2) $ indicesNames t1
            else []
        t1' = foldl' (|>>>) t1 commonIndices
        t2' = foldl' (|>>>) t2 commonIndices
    in _mergeScalars $ _elemByElem' t1' t2' f op
_elemByElem :: (Num a, Multilinear Tensor a, NFData a)
            => Tensor a                             -- ^ First argument of operator
            -> Tensor a                             -- ^ Second argument of operator
            -> (a -> a -> a)                        -- ^ Operator on tensor elements if indices are different
            -> (Tensor a -> Tensor a -> Tensor a)   -- ^ Tensor operator called if indices are the same
            -> Tensor a
_elemByElem t1 t2 f op = 
    let commonIndices = 
            if indices t1 /= indices t2 then
                Data.List.filter (`Data.List.elem` indicesNames t2) $ indicesNames t1
            else []
        t1' = foldl' (|>>>) t1 commonIndices
        t2' = foldl' (|>>>) t2 commonIndices
    in _mergeScalars $ _elemByElem' t1' t2' f op
_elemByElem t1 t2 f op = 
    let commonIndices = 
            if indices t1 /= indices t2 then
                Data.List.filter (`Data.List.elem` indicesNames t2) $ indicesNames t1
            else []
        t1' = foldl' (|>>>) t1 commonIndices
        t2' = foldl' (|>>>) t2 commonIndices
    in _mergeScalars $ _elemByElem' t1' t2' f op