问题
I am new to Haskell, so my question is probably stupid.
I want a function
show2 :: (Show a) => a -> String
which would return show a
for any a
, but a
if a is itself String
.
How can I implement it?
P.S. it is great if this function is already implemented somewhere, but I still want to see an example of the implementation.
回答1:
You can do this with this piece of dirty and dangerous code:
class Showable a where
show2 :: a -> String
instance Showable String where
show2 = id
instance (Show a) => Showable a where
show2 = show
You need -XOverlappingInstances -XFlexibleInstances -XUndecidableInstances
to compile and use it.
*Main> show2 "abc"
"abc"
*Main> show2 3
"3"
回答2:
You can use cast
from Data.Typeable
show2 :: (Typeable a, Show a) => a -> String
show2 s = maybe (show s) id ms
where ms = cast s :: Maybe String
回答3:
The way that Haskell is designed is very much opposed to the concept of an instanceof
check. Haskell's design does not incorporate this sort of runtime type check, because Haskell is very focused on strong compilation-time guarantees: a function should not be able to learn the type of its arguments at runtime any more precisely than it knows them at compilation time.
This doesn't meant that the feature doesn't exist in Haskell—Lee's answer demonstrates how to do it—but in Haskell this is an opt-in feature provided by a library, not a core part of the language (unlike a language like Java, where it's a core feature that's always present—you can't opt out of it!).
Note that even in object-oriented programming the instanceof
operator is controversial. Many object-oriented programmers very strongly advise against its use. A few examples (out of hundreds):
- use of "Instance of" in java
- Avoiding instanceof in Java
- http://smsohan.com/blog/2011/11/01/using-instanceof-is-mostly-code-smell/
- http://sourcemaking.com/refactoring/replace-conditional-with-polymorphism
- http://www.javapractices.com/topic/TopicAction.do?Id=31
- http://www.artima.com/interfacedesign/PreferPoly.html
The advise in all of these tends to be the same: instead of using testing the type of a reference and switching to different behaviors based on it, use polymorphism: define an interface or class that has a method for the operation you want, and have the objects that you were testing with instanceof
implement their own versions of that method to do the right thing.
This advice can be translated straightforwardly to Haskell:
- Define your own type class to represent the behavior you want
- Implement this type class for each of the types that you're interested in, with the correct behavior for each.
So, you could do something like this:
class ToString a where
toString :: a -> String
instance ToString String where
toString str = str
instance ToString Integer where
toString i = show i
-- ...
来源:https://stackoverflow.com/questions/29284765/haskell-instanceof-analogue