I am not sure, I understand this:
f :: Integer -> Double -> String -> String
f a d s = undefined
What can the potential body of f
be here? I am confused by this new syntax never encountered before.
EDIT: So, since a
is an Integer
, and d
is a Double
, can the body of the method be written as such, that a String
is returned depending on the type? Like a comparison.
Python:
def f(a: int, d: float, s: str) -> str:
if(s == "Is Integer less than Double"):
if(a < d):
return "Yes, it is."
else:
return "No, it isn't"
How to do the same in Haskell?
CodePudding user response:
You could actually translate your Python code, mapping the syntactic structure almost literally to Haskell. What changes is
- You don't need
return
(because in Haskell you always directly specify what the function returns, and only need extra syntax for managing monadic side effects – which this function doesn't have). - On the flip side, you do need to have an
else
in everyif
statement, because unlike in Python you can't just not return anything (well, arguably you can't do that in Python either, it just defaults to returningNone
if you don't explicitly return something else). - You can't directly use
<
on two different typed variables. Unlike Python, Haskell never does automatic type conversion, however you can explicitly do it withfromIntegral
.
So,
f a d s =
if(s == "Is Integer less than Double")
then if(fromInteger a < d)
then "Yes, it is."
else "No, it isn't"
else {- ...whatever should happen in this case -}
Haskellers tend to not use if
constructs though, but instead use guards for conditionals, i.e.
f a d s
| s == "Is Integer less than Double"
= if(fromInteger a < d)
then "Yes, it is."
else "No, it isn't"
| otherwise = {- ...whatever should happen in this case -}
That actually allows you to also omit the explicit fallback case, though the compiler will then warn about an incomplete match.
Anyway it's still not idiomatic: Haskellers avoid binding a function argument just to check it for equality. Instead, you just pattern match on the value you compare against:
f a d "Is Integer less than Double"
= if(fromInteger a < d)
then "Yes, it is."
else "No, it isn't"
f a d s = {- ...whatever should happen in this case -}
Now you can actually use guards for what was originally the inner if
:
f a d "Is Integer less than Double"
| fromInteger a < d
= "Yes, it is."
| otherwise = "No, it isn't"
f a d s = {- ...whatever should happen in this case -}
If you really don't want to handle the case of any other string, then you should make that a failure case that's expressed also through the type signature:
f :: Integer -> Double -> String -> Maybe String
f a d "Is Integer less than Double"
| fromInteger a < d
= Just "Yes, it is."
| otherwise = Just "No, it isn't"
f _ _ _ = Nothing
CodePudding user response:
So, since
a
is anInteger
, andd
is aDouble
, can the body of the method be written as such, that a String is returned depending on the type? Like a comparison.
Yess, there is however a small caveat. The (<) :: Ord a => a -> a -> Bool
requires that the two operands have the same type, so we will need to convert for example the Integer
to a double first, we can do this with fromInteger :: Num a => Integer -> a
to convert it to any type that is a member of the Num
typeclass.
We can implement this with guards as:
f :: Integer -> Double -> String -> String
f a d "Is Integer less than Double"
| fromInteger a < d = "Yes, it is."
| otherwise = "No, it isn't"
The function is however not total, only if the third parameter is "Is Integer less than Double"
, then it will thus compare the two. Programmers in Haskell tend to prefer functions that return something for every possible input, since then they do not have to worry much about passing certain inputs.