def METHOD_NAME(l):
    r"""
    Return a rank function for the elements of ``l``.
    INPUT:
    - ``l`` -- a duplicate free list (or iterable) of hashable objects
    OUTPUT:
    - a function from the elements of ``l`` to ``0,...,len(l)``
    EXAMPLES::
        sage: import sage.combinat.ranker as ranker
        sage: l = ['a', 'b', 'c']
        sage: r = ranker.rank_from_list(l)
        sage: r('a')
        0
        sage: r('c')
        2
    For non elements a ``ValueError`` is raised, as with the usual
    ``index`` method of lists::
        sage: r('blah')
        Traceback (most recent call last):
        ...
        ValueError: 'blah' is not in dict
    Currently, the rank function is a
    :class:`~sage.misc.callable_dict.CallableDict`; but this is an
    implementation detail::
        sage: type(r)
        <class 'sage.misc.callable_dict.CallableDict'>
        sage: r
        {'a': 0, 'b': 1, 'c': 2}
    With the current implementation, no error is issued in case of
    duplicate value in ``l``. Instead, the rank function returns the
    position of some of the duplicates::
        sage: r = ranker.rank_from_list(['a', 'b', 'a', 'c'])
        sage: r('a')
        2
    Constructing the rank function itself is of complexity
    ``O(len(l))``. Then, each call to the rank function consists of an
    essentially constant time dictionary lookup.
    TESTS::
        sage: TestSuite(r).run()
    """
    return CallableDict((x,i) for i,x in enumerate(l))