       "list" => fn args -> args end,
       "read-string" => fn [input] -> Mal.Reader.read_str(input) end,
       "throw" => fn [arg] -> throw({:error, arg}) end,
+      "contains?" => fn [map, key] -> Map.has_key?(map, key) end,
+      "keys" => fn [map] -> Map.keys(map) end,
+      "vals" => fn [map] -> Map.values(map) end
     }
   end
 

      "symbol?" => &symbol?/1,
      "cons" => &cons/1,
      "vector?" => &vector?/1,
      "sequential?" => fn arg -> vector?(arg) or list?(arg) end,
      "vector" => fn list -> {:vector, list} end,
      "keyword?" => fn [type] -> is_atom(type) end,
      "nil?" => fn [type] -> type == nil end,
      "true?" => fn [type] -> type == true end,
      "false?" => fn [type] -> type == false end,

    Enum.map(args, &convert_vector/1)
      |> Enum.concat
  end

  def assoc([hash_map | pairs]) do
    Map.merge(hash_map, Mal.Types.hash_map(pairs))
  end

  def dissoc([hash_map | keys]) do
    Map.drop(hash_map, keys)
  end

  def get([map, key]) when is_map(map), do: Map.get(map, key, nil)
  def get([_map, _key]), do: nil
end
