Since it turns out System.AsyncException is uncatchable (just tested it) there isn't much you can do to either predict when this is going to happen or resolve it outside of editing the conflicting code.
In short: there's not really a solution other than requiring customers to fix their code to not use @future form non-async safe contexts. And yes, I realize how well that response goes over, I've had to give it more than once.
I follow a pattern known as the Service Layer. If you can elaborate on your 'function a' signature and needs I can provide some more specific examples for you, but this should give the general idea.
Service Layer, “Defines an application's boundary with a layer of services that establishes a set of available operations and coordinates the application's response in each operation.” Martin Fowler / Randy Stafford, EAA Patterns
In an Apex world it essentially encapsulates all your applications process logic in single layer that is agnostic of the callers, be they Batch Apex, Future, Apex Triggers, VF Controllers etc.... If you follow this practice closely you can even turn such things into a public Apex or REST API for your application quite easily.

This is an example of such a service method.
public class OpportunityService
{
public static void applyDiscounts(Set<ID> opportunityIds, Decimal discountPercentage)
This is then consumed by a VF controller like so...
public PageReference applyDiscounts()
{
try
{
// Apply discount entered to the selected Opportunities
OpportunitiesService.applyDiscounts(
new Map<Id,SObject>(standardSetController.getSelected()).keyValues(),
DiscountPercentage);
}
catch (Exception e)
{
ApexPages.addMessages(e);
}
return ApexPages.hasMessages() ? null : standardController.view();
}
Or a Batch Apex class like so...
public with sharing class DiscountOpportunities
implements Database.Batchable<sObject>
{
public Decimal DiscountPercentage {get;set;}
public Database.QueryLocator start(Database.BatchableContext BC) { ... }
public void execute(Database.BatchableContext BC, List<sObject> scope)
{
try
{
OpportunitiesService.applyDiscounts(
new Map<Id,SObject>(scope).keyValues(),DiscountPercentage);
}
catch (Exception e)
{
// Email error, log error, chatter error etc..
}
}
public void finish(Database.BatchableContext BC) { ... }
}
There are a few other examples in the article linked below.
Designing a Service Layer. In either case the transactional scope and containment of the logic is managed entirely by the service layer, the callers responsibility is only to pass in the correct information, interpret responses and handle any Apex exceptions accordingly. Note also that service methods take bulkified parameters to match most callers needs and to better enforce bulkifcaiton within the service logic itself.
Further Reading. You can read more about this sample code, the guidelines and and other Apex Enterprise Patterns link within here. I'd be keen to know more about the signature of function A so I can perhaps taylor this answer a bit further for you.
Hope this helps!
Best Answer
Check if you are already in an asynchronous process before calling your future method. Here's the basic idea sketched out: