How to use return in my custom function instead of echo

If you use do_action( 'woo_collections_menu' ); in the template, then your function must echo its value. Otherwise, you are returning the data into a black hole, nothing is outputting what you’re returning.

If you use a filter, then you should return the value. The point of a filter is to take a value, filter that value through a function, then do something with the result. In the context of your template, using apply_filters would be a bit strange, because your menu has no value until you construct it. So in the template it would look like:

echo apply_filters( 'collections_menu', '' );

Which is just potentially confusing and unnecessary. That empty string could be a default menu or something, but putting that in the template is probably not the wisest choice.

However, a filter would make sense within the function itself, to allow someone to change the output.

function display_collections_menu(){
    $default_menu = 'my complete menu markup here';
    return apply_filters( 'collections_menu', $default_menu );
}

Then in the template, you could just output the function directly:

echo display_collections_menu();

and someone can add their own filter to modify output if they’d like. Another helpful inclusion could be a filter on the arguments that you fetch terms with, so someone can change menu output without having to reproduce the whole function.

But going back to your original code, adding do_action( 'woo_collections_menu' ); and then echoing menu output directly in the function should also work.