from typing import Dict
from typing import Callable
import torch


def evaluate_dict(
    fns_dict: Dict[str, Callable], source: torch.Tensor, target: torch.Tensor, reduction: str = "mean"
) -> Dict:
    """Evaluate a dictionary of functions.

    Examples
    --------
    > evaluate_dict({'l1_loss: F.l1_loss, 'l2_loss': F.l2_loss}, a, b)

    Will return
    > {'l1_loss', F.l1_loss(a, b, reduction='mean'), 'l2_loss': F.l2_loss(a, b, reduction='mean')

    Parameters
    ----------
    fns_dict: Dict[str, Callable]
    source: torch.Tensor
    target: torch.Tensor
    reduction: str

    Returns
    -------
    Dict[str, torch.Tensor]
        Evaluated dictionary.
    """
    return {k: fns_dict[k](source, target, reduction=reduction) for k, v in fns_dict.items()}