implement map, todo: dry it up