What's wrong with this function?

Hai, I’m Kai! Totally new to Elixir here, and gave up coding in other languages for so long now I’m practically new to programming as a whole again. I’ve been using Joy of Elixir as an introduction, and I don’t feel like I’m banging my head against a brick wall so far, so that’s a plus!

However, I did this silly thing here to test my understanding of cond statements, and I’m stumped as to why it doesn’t work.

ffan = %{
  name: "Kff'annin",
  current_hp: 240,
  max_hp: 4080,
  current_energy: 500,
  max_energy: 720,
  current_will: 720,
  max_will: 720,
  is_mob: false,
  fav_ice_cream_flavor: "Cotton Candy Bubble Gum",
}

alter_hp = fn(name,current_hp,max_hp,ficf,hp_effect) ->
  cond do
    hp_effect > 0 ->
      if current_hp < max_hp do
        current_hp = current_hp + hp_effect
        IO.puts "#{name} was healed for #{hp_effect} HP. #{name}'s HP is now #{current_hp}."
      else
        IO.puts "#{name}'s HP is already at its maximum, #{max_hp}."
      end
    hp_effect < 0 ->
      if current_hp > 0 do
        current_hp = current_hp + hp_effect
        IO.puts "#{name} was hurt for #{hp_effect} HP. #{name}'s HP is now #{current_hp}."
      else
        IO.puts "#{name} is already defeated! Could you spare some #{ficf} ice cream for their recovery?"
      end
    hp_effect == 0 ->
      IO.puts "No effect on #{name}'s HP. It is currently #{current_hp}."
  end
end

alter_hp(ffan.name,ffan.current_hp,ffan.max_hp,ffan.fav_ice_cream_flavor,82)

When attempting to run it, I get an error telling me that function alter_hp is undefined…but it clearly, obviously is defined right above the call! I combed through said function about five times too, looking for stuff like syntax goofs or missing end-statement closures, but it all looks fine to me. What am I missing here?

Also, is there a better place to be an annoying beginner programmer than this?

1 Like

Hi Kai! :wave: Welcome to the forum!

To call an anonymous function in Elixir you need to use a “.” after the variable name and before the “(“.

So in your case you need to alter_hp.(ffan.name,ffan.current_hp,ffan.max_hp,ffan.fav_ice_cream)

Also another potential issue I see is that you’re reassigning current_hp inside the body of the if statement. It’s not necessarily a problem right now but it’s a common gotcha for beginners. You can read up a bit on it here: Elixir Gotchas and Common Issues Wiki

12 Likes

Ugh, I can’t believe I forgot that detail after using nothing but anonymous functions! Thanks

I became wise to the current_hp issue after attempting to chain alter_hp actions and getting the wrong result (as if Ffan’s HP reset every time), so I have to find a solution to that :woozy_face:

Also, is it possible to pass the whole map ffan to the alter_hp function and do operations on its sub-elements that way? It’d make things much more concise. For example:

alter_hp = fn(entity,hp_effect) ->
  cond do
    hp_effect > 0 ->
      if entity.current_hp < entity.max_hp do
        entity.current_hp += hp_effect # to be refuckulated
        IO.puts "#{entity.name} was healed for #{hp_effect} HP. #{entity.name}'s HP is now #{entity.current_hp}."
      else
        IO.puts "#{entity.name}'s HP is already at its maximum, #{entity.max_hp}."
# and so on and so forth

alter_hp.(ffan,82)
4 Likes

Hi, you’d want to structure it more like this:

    alter_hp = fn entity, hp_effect ->
      cond do
        hp_effect > 0 ->
          if entity.current_hp < entity.max_hp do
            new_entity = %{entity | current_hp: entity.current_hp + hp_effect}

            IO.puts("#{new_entity.name} was healed for #{hp_effect} HP. #{new_entity.name}'s HP is now #{new_entity.current_hp}.")
            # Return updated entity
            new_entity
          else
            IO.puts("#{entity.name}'s HP is already at its maximum, #{entity.max_hp}.")
            # Return unchanged entity
            entity
          end
          # and so on and so forth
      end
    end

    ffan = alter_hp.(ffan, 82)
    IO.inspect(ffan, label: "altered ffan")

So from your alter_hp anonymous function you want to return an updated version of the entity as the result of the cond block. It’s not clear from the code that you’ve posted if entity is a struct or not, but it’s either a struct or a map and they can be updated similarly by using the | within the map syntax. For example that could look like: %{initial_value | some_key: new_value} (see Structs - The Elixir programming language for details). I often use that syntax because when I am updating a struct I already know what keys exist for that struct, and if I make an error I want it to fail fast instead of creating an invalid struct.

5 Likes

Awesome, I was able to test all branches of the function and they all worked when rewritten in this manner! Just wondering if this is a normal return:

Kff'annin was hurt for -56 HP. Kff'annin's HP is now 184. altered ffan: :ok

Thanks a lot. Structs/maps seem like all the “objects” i’ll ever need!