Your code as given does not produce the error you said it does. However, if I clean it up a bit, it will produce that error:
italy : String
italy = "italy"
canada : String
canada = "canada"
countryConvert : String -> String
countryConvert country =
case country of
italy -> "Италия"
canada -> "Канада"
To be more precise, it produces that error with Elm 0.18. If you try to compile with 0.19, you'll get a slightly more informative error:
$ elm make Countries.elm
The name `italy` is first defined here:
5| italy = "italy"
^^^^^
But then it is defined AGAIN over here:
17| italy -> "Италия"
^^^^^
Think of a more helpful name for one of them and you should be all set!
This can still be a bit mysterious though. The key thing to understand is that case expressions have two purposes, which sometimes overlap: to compare individual values or to test structure ("shape", in the 0.18 error message's parlance) and "destructure" values -- giving local names to the parts of that structure. The Elm Guide has a nice simple example.
In order to compare individual values, you must have those values in-line in each clause of the case expression. Any variables that you use are assumed to be new declarations, local to that clause of the case expression.
So in your case expression, you aren't matching against the values that italy and canada have across the rest of your program. Instead, you're declaring two new local variables that just happen to also be named italy and canada. In other words, you haven't "taken apart" the country string at all -- all you've done is just declare a new local name for it (italy). And that's why 0.19 is complaining about shadowing. (See this explanation for why shadowing is an error rather than just a warning in 0.19.)
Since there is also no structural difference between the clauses of the case expression, 0.18 is effectively complaining that your two case clauses are identical. One will match any string an assign it to a new local variable italy; the other will also match any string, and assign it to a new local variable canada.
Alternatives that will work:
You can just inline the values:
countryConvert : String -> String
countryConvert country =
case country of
"italy" -> "Италия"
"canada" -> "Канада"
_ -> country
You can use a simple if-else construct:
countryConvert : String -> String
countryConvert country =
if country == italy then
"Италия"
else if country == canada then
"Канада"
else
country
Or use a Dict:
countries : Dict String String
countries =
fromList
[ ( "italy", "Италия" )
, ( "canada", "Канада" )
]
countryConvert : String -> String
countryConvert country =
case get country countries of
Just c ->
c
Nothing ->
country
Note that you do still need a case expression with this approach. That's because Dict.get might be passed a key that isn't in the Dict. So you might consider having your function's return type be Maybe String as well, so that it's clear that the caller might pass in a country you don't know how to translate. And that it's the caller's responsibility to decide what to do in that case.
"italy"and"canada"(with quotes); notitalyandcanada(without quotes). Note you'll also need to add_ -> "default". - Mulan