How to get the value of a Maybe in Haskell - return-value

I'm relatively new to Haskell and began to read "Real World Haskell".
I Just stumbled over the type Maybe and have a question about how to receive the actual value from a Just 1 for example.
I have written the following code:
combine a b c = (eliminate a, eliminate b, eliminate c)
where eliminate (Just a) = a
eliminate Nothing = 0
This works fine if I use:
combine (Just 1) Nothing (Just 2)
But if I change, for example, 1 to a String it doesn't work.
I think I know why: because eliminate has to give back one type, which is, in this case, an Int. But how can I change eliminate to deal at least with Strings (or maybe with all kind of types)?

From the standard Prelude,
maybe :: b -> (a -> b) -> Maybe a -> b
maybe n _ Nothing = n
maybe _ f (Just x) = f x
Given a default value, and a function, apply the function to the value in the Maybe or return the default value.
Your eliminate could be written maybe 0 id, e.g. apply the identity function, or return 0.
From the standard Data.Maybe,
fromJust :: Maybe a -> a
fromJust Nothing = error "Maybe.fromJust: Nothing"
fromJust (Just x) = x
This is a partial function (does not return a value for every input, as opposed to a total function, which does), but extracts the value when possible.

[edit from Author, 6 years later] This is a needlessly long answer, and I'm not sure why it was accepted. Use maybe or Data.Maybe.fromMaybe as suggested in the highest upvoted answer. What follows is more of a thought experiment rather than practical advice.
So you're trying to create a function that works for a bunch of different types. This is a good time to make a class. If you've programmed in Java or C++, a class in Haskell is kind of like an interface in those languages.
class Nothingish a where
nada :: a
This class defines a value nada, which is supposed to be the class's equivalent of Nothing. Now the fun part: making instances of this class!
instance Nothingish (Maybe a) where
nada = Nothing
For a value of type Maybe a, the Nothing-like value is, well, Nothing! This will be a weird example in a minute. But before then, let's make lists an instance of this class too.
instance Nothingish [a] where
nada = []
An empty list is kind of like Nothing, right? So for a String (which is a list of Char), it will return the empty string, "".
Numbers are also an easy implementation. You've already indicated that 0 obviously represents "Nothingness" for numbers.
instance (Num a) => Nothingish a where
nada = 0
This one will actually not work unless you put a special line at the top of your file
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
Or when you compile it you can set the flags for these language pragmas. Don't worry about them, they're just magic that makes more stuff work.
So now you've got this class and these instances of it...now let's just re-write your function to use them!
eliminate :: (Nothingish a) => Maybe a -> a
eliminate (Just a) = a
eliminate Nothing = nada
Notice I only changed 0 to nada, and the rest is the same. Let's give it a spin!
ghci> eliminate (Just 2)
2
ghci> eliminate (Just "foo")
"foo"
ghci> eliminate (Just (Just 3))
Just 3
ghci> eliminate (Just Nothing)
Nothing
ghci> :t eliminate
eliminate :: (Nothingish t) => Maybe t -> t
ghci> eliminate Nothing
error! blah blah blah...**Ambiguous type variable**
Looks great for values and stuff. Notice the (Just Nothing) turns into Nothing, see? That was a weird example, a Maybe in a Maybe. Anyways...what about eliminate Nothing? Well, the resultant type is ambiguous. It doesn't know what we are expecting. So we have to tell it what type we want.
ghci> eliminate Nothing :: Int
0
Go ahead and try it out for other types; you'll see it gets nada for each one. So now, when you use this function with your combine function, you get this:
ghci> let combine a b c = (eliminate a, eliminate b, eliminate c)
ghci> combine (Just 2) (Just "foo") (Just (Just 3))
(2,"foo",Just 3)
ghci> combine (Just 2) Nothing (Just 4)
error! blah blah Ambiguous Type blah blah
Notice you still have to indicate what type your "Nothing" is, or indicate what return type you expect.
ghci> combine (Just 2) (Nothing :: Maybe Int) (Just 4)
(2,0,4)
ghci> combine (Just 2) Nothing (Just 4) :: (Int, Int, Int)
(2,0,4)
Or, you could restrict the types that your function allows by putting its type signature explicitly in the source. This makes sense if the logical use of the function would be that it is only used with parameters of the same type.
combine :: (Nothingish a) => Maybe a -> Maybe a -> Maybe a -> (a,a,a)
combine a b c = (eliminate a, eliminate b, eliminate c)
Now it only works if all three Maybe things are the same type. That way, it will infer that the Nothing is the same type as the others.
ghci> combine (Just 2) Nothing (Just 4)
(2,0,4)
No ambiguity, yay! But now it is an error to mix and match, like we did before.
ghci> combine (Just 2) (Just "foo") (Just (Just 3))
error! blah blah Couldn't match expected type blah blah
blah blah blah against inferred type blah blah
Well, I think that was a sufficiently long and overblown answer. Enjoy.

I'm new to Haskell too, so I don't know if this exists in the platform yet (I'm sure it does), but how about a "get or else" function to get a value if it exists, else return a default?
getOrElse::Maybe a -> a -> a
getOrElse (Just v) d = v
getOrElse Nothing d = d

This is the answer I was looking for when I came to this question:
https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Maybe.html#v:fromJust
...and similarly, for Either:
https://hackage.haskell.org/package/either-unwrap-1.1/docs/Data-Either-Unwrap.html
They provide functions I would have written myself which unwrap the value from its context.

The eliminate function's type signature is:
eliminate :: Maybe Int -> Int
That's because it returns 0 on Nothing, forcing the compiler to assume that a :: Int in your eliminate function. Hence, the compiler deduces the type signature of the combine function to be:
combine :: Maybe Int -> Maybe Int -> Maybe Int -> (Int, Int, Int)
and that's precisely why it doesn't work when you pass a String to it.
If you wrote it as:
combine a b c = (eliminate a, eliminate b, eliminate c)
where eliminate (Just a) = a
eliminate Nothing = undefined
then it would have worked with String or with any other type. The reason relies on the fact that undefined :: a, which makes eliminate polymorphic and applicable to types other than Int.
Of course, that's not the aim of your code, i.e., to make the combine function total.
Indeed, even if an application of combine to some Nothing arguments would succeed (that's because Haskell is lazy by default), as soon as you try to evaluate the results you would get a runtime error as undefined can't be evaluated to something useful (to put it in simple terms).

Related

Why don't these types unify when using type constraints and a typeclass instance?

So, I am attempting to develop a function that expects a polymorphic function.
I start with and create a class Foo, to represent the constrained type argument in the example function.
module Test
where
class Foo a
Along with a random type for this example...
newtype Bar = Bar Int
In order to pass Bar to anything that has a Foo constraint, it needs to have a typeclass, so I do so:
instance fooBar :: Foo Bar
Everything should be perfectly fine, however, this doesn't work, psc doesn't think the types unify and I don't know why:
example :: forall a. (Foo a) => (a -> Int) -> Int
example a = a (Bar 42)
Error as follows:
Error found:
in module Test
at /Users/arahael/dev/foreign/test.purs line 11, column 16 - line 11, column 22
Could not match type
Bar
with type
a0
while checking that type Bar
is at least as general as type a0
while checking that expression Bar 42
has type a0
in value declaration example
where a0 is a rigid type variable
bound at line 11, column 1 - line 11, column 22
See https://github.com/purescript/documentation/blob/master/errors/TypesDoNotUnify.md for more information,
or to contribute content related to this error.
Compare
(1) example :: (forall a. (Foo a) => a -> Int) -> Int
with
(2) example :: forall a. (Foo a) => (a -> Int) -> Int
The latter essentially places responsibility on you, the caller, to supply as the argument to example a function (your choice!) w/ the signature a -> Int (such that there is a Foo instance for a).
The former, on the other hand, says that you, the caller, don't actually get to pick what this function a -> Int is. Rather, as Norman Ramsey has explained in a Haskell-related stackoverflow answer here, when the forall is "to the left" of the arrow (rather than "above the arrow") the implementation decides what function to supply. The signature in (2) is saying any function a -> Int will do as the argument to example (so long as there is a Foo intance for a).
If (1) just "magically" works, then, it's because the function that unwraps the newtype Bar is being selected by the compiler as perfectly satisfactory, and passed as the argument to example in case (1). After all, the signature of (1) suggests that example should return the same Int values no matter what function a -> Int is given (so long as there is a Foo instance for a). In case (2), the Int values returned by example may very well differ depending upon the specific function a -> Int supplied. The compiler cannot grab any such function that it knows satisfies the type at random. It cannot guess the type of a or a -> Int that you, the caller, actually have in mind.

Encoding of inferrable records

As you probably know, records are somewhat special in ocaml, as each label has to be uniquely assigned to a nominal record type, i.e. the following function cannot be typed without context:
let f r = r.x
Proper first class records (i.e. things that behave like tuples with labels) are trivially encoded using objects, e.g.
let f r = r#x
when creating the objects in the right way (i.e. no self-recursion, no mutation), they behave just like records.
I am however, somewhat unhappy with this solution for two reasons:
when making records updatetable (i.e. by adding an explicit "with_l" method for each label l), the type is somewhat too loose (it should be the same as the original record). Admitted, one can enforce this equality, but this is still inconvenient.
I have the suspicion that the OCaml compiler does not infer that these records are actually immutable: In a function
let f r = r#x + r#x
would the compiler be able to run a common subexpression elimination?
For these reasons, I wonder if there is a better encoding:
Is there another (aside from using objects) type-safe encoding (e.g. using polymorphic variants) of records with inferrable type in OCaml?
Can this encoding avoid the problems mentioned above?
If I understand you correctly you're looking for a very special kind of polymorphism. You want to write a function that will work for all types, such that the type is a record with certain fields. This sounds more like a syntactic polymorphism in a C++ style, not as semantic polymorphism in ML style. If we will slightly rephrase the task, by capturing the idea that a field accessing is just a syntactic sugar for a field projection function, then we can say, that you want to write a function that is polymorphic over all types that provide a certain set of operations. This kind of polymorphism can be captured by OCaml using one of the following mechanisms:
functors
first class modules
objects
I think that functors are obvious, so I will show an example with first class modules. We will write a function print_student that will work on any type that satisfies the Student signature:
module type Student = sig
type t
val name : t -> string
val age : t -> int
end
let print_student (type t)
(module S : Student with type t = t) (s : t) =
Printf.printf "%s %d" (S.name s) (S.age s)
The type of print_student function is (module Student with type t = 'a) -> 'a -> unit. So it works for any type that satisfies the Student interface, and thus it is polymorphic. This is a very powerful polymorphism that comes with a price, you need to pass the module structure explicitly when you're invoking the function, so it is a System F style polymorphism. Functors will also require you to specify concrete module structure. So both are not inferrable (i.e., not an implicit Hindley-Milner-like style polymorphism, that you are looking for). For the latter, only objects will work (there are also modular implicits, that relax the explicitness requirement, but they are still not in the trunk, but they will actually answer your requirements).
With object-style row polymorphism it is possible to write a function that is polymorphic over a set of types conforming to some signature, and to infer this signature implicitly from the function definintion. However, such power comes with a price. Since object operations are encoded with methods and methods are just function pointers that are assigned dynamically in the runtime, you shouldn't expect any compile time optimizations. It is not possible to perform any static analysis on something that is bound dynamically. So, of course, no Common Subexpression elimination, nor inlining. For functors and first class modules, the optimization is possible on a newer branch of the compiler with flamba (See 4.03.0+flambda opam switch). But on a regular compiler installation no inlining will be performed.
Different approaches
What concerning other techniques. First of all we can use camlp{4,5}, or ppx or even m4 and cpp to preprocess code, but this would be hardly idiomatic and of doubtful usefulness.
Another way, is instead of writing a function that is polymorphic, we can try to find a suitable monomorphic data type. A direct approach would be to use a list of polymorphic variants, e.g.,
type attributes = [`name of string | `age of int]
type student = attribute list
In fact we even don't need to specify all these types ahead, and our function can require only those fields that are needed, a form of a row polymorphism:
let rec name = function
| [] -> raise Not_found
| `name n -> n
| _ :: student -> name student
The only problem with this encoding, is that you cannot guarantee that the same named attribute can occur once and only once. So it is possible that a student doesn't have a name at all, or, that is worser, it can have more then one names. Depending on your problem domain it can be acceptable.
If it is not, then we can use GADT and extensible variants to encode heterogenous maps, i.e., an associative data structures that map keys to
different type (in a regular (homogenous) map or assoc list value type is unified). How to construct such containers is beyond the scope of the answer, but fortunately there're at least two available implementations. One, that I use personally is called universal map (Univ_map) and is provided by a Core library (Core_kernel in fact). It allows you to specify two kinds of heterogenous maps, with and without a default values. The former corresponds to a record with optional field, the latter has default for each field, so an accessor is a total function. For example,
open Core_kernel.Std
module Dict = Univ_map.With_default
let name = Dict.Key.create ~name:"name" ~default:"Joe" sexp_of_string
let age = Dict.Key.create ~name:"age" ~default:18 sexp_of_int
let print student =
printf "%s %d"
(Dict.get student name) (Dict.get age name)
You can hide that you're using universal map using abstract type, as there is only one Dict.t that can be used across different abstractions, that may break modularity. Another example of heterogeneous map implementation is from Daniel Bunzli. It doesn't provide With_default kind of map, but has much less dependencies.
P.S. Of course for such a redundant case, where this only one operation it is much easier to just pass this operation explicitly as function, instead of packing it into a structure, so we can write function f from your example as simple as let f x r = x r + x r. But this would be the same kind of polymoprism as with first class modules/functors, just simplified. And I assume, that your example was specifically reduced to one field, and in your real use case you have more complex set of fields.
Very roughly speaking, an OCaml object is a hash table whose keys are its method name hash. (The hash of a method name can be obtained by Btype.hash_variant of OCaml compiler implementation.)
Just like objects, you can encode polymorphic records using (int, Obj.t) Hashtbl.t. For example, a function to get a value of a field l can be written as follows:
(** [get r "x"] is poly-record version of [r.x] *)
let get r k = Hashtbl.find t (Btype.hash_variant k))
Since it is easy to access the internals unlike objects, the encoding of {r with l = e} is trivial:
(** [copy_with r [(k1,v1);..;(kn,vn)]] is poly-record version of
[{r with k1 = v1; ..; kn = vn}] *)
let copy_with r fields =
let r = Hashtbl.copy r in
List.iter (fun (k,v) -> Hashtbl.replace r (Btype.hash_variant k) v) fields
and the creation of poly-records:
(** [create [(k1,v1);..(kn,vn)]] is poly-record version of [{k1=v1;..;kn=vn}] *)
let create fields = copy_with fields (Hashtbl.create (List.length fields))
Since all the types of the fields are squashed into one Obj.t, you have to use Obj.magic to store various types into this implementation and therefore this is not type-safe by itself. However, we can make it type-safe wrapping (int, Obj.t) Hashtbl.t with phantom type whose parameter denotes the fields and their types of a poly-record. For example,
<x : int; y : float> Poly_record.t
is a poly-record whose fields are x : int and y : float.
Details of this phantom type wrapping for the type safety is too long to explain here. Please see my implementation https://bitbucket.org/camlspotter/ppx_poly_record/src . To tell short, it uses PPX preprocessor to generate code for type-safety and to provide easier syntax sugar.
Compared with the encoding by objects, this approach has the following properties:
The same type safety and the same field access efficiency as objects
It can enjoy structural subtyping like objects, what you want for poly-records.
{r with l = e} is possible
Streamable outside of a program safely, since hash tables themselves have no closure in it. Objects are always "contaminated" with closures therefore they are not safely streamable.
Unfortunately it lacks efficient pattern matching, which is available for mono-records. (And this is why I do not use my implementation :-( ) I feel for it PPX reprocessing is not enough and some compiler modification is required. It will not be really hard though since we can make use of typing of objects.
Ah and of course, this encoding is very side effective therefore no CSE optimization can be expected.
Is there another (aside from using objects) type-safe encoding (e.g. using polymorphic variants) of records with inferrable type in OCaml?
For immutable records, yes. There is a standard theoretical duality between polymorphic records ("inferrable" records as you describe) and polymorphic variants. In short, a record { l_1 = v_1; l_2 = v_2; ...; l_n = v_n } can be implemented by
function `l_1 k -> k v_1 | `l_2 k -> k v_2 | ... | `l_n k -> k v_n
and then the projection r.l_i becomes r (`l_i (fun v -> v)). For instance, the function fun r -> r.x is encoded as fun r -> r (`x (fun v -> v)). See also the following example session:
# let myRecord = (function `field1 k -> k 123 | `field2 k -> k "hello") ;;
(* encodes { field1 = 123; field2 = "hello" } *)
val myRecord : [< `field1 of int -> 'a | `field2 of string -> 'a ] -> 'a = <fun>
# let getField1 r = r (`field1 (fun v -> v)) ;;
(* fun r -> r.field1 *)
val getField1 : ([> `field1 of 'a -> 'a ] -> 'b) -> 'b = <fun>
# getField1 myRecord ;;
- : int = 123
# let getField2 r = r (`field2 (fun v -> v)) ;;
(* fun r -> r.field2 *)
val getField2 : ([> `field2 of 'a -> 'a ] -> 'b) -> 'b = <fun>
# getField2 myRecord ;;
- : string = "hello"
For mutable records, we can add setters like:
let ref1 = ref 123
let ref2 = ref "hello"
let myRecord =
function
| `field1 k -> k !ref1
| `field2 k -> k !ref2
| `set_field1(v1, k) -> k (ref1 := v1)
| `set_field2(v2, k) -> k (ref2 := v2)
and use them like myRecord (`set_field1(456, fun v -> v)) and myRecord (`set_field2("world", fun v -> v)) for example. However, localizing ref1 and ref2 like
let myRecord =
let ref1 = ref 123 in
let ref2 = ref "hello" in
function
| `field1 k -> k !ref1
| `field2 k -> k !ref2
| `set_field1(v1, k) -> k (ref1 := v1)
| `set_field2(v2, k) -> k (ref2 := v2)
causes a value restriction problem and requires a little more polymorphic typing trick (which I omit here).
Can this encoding avoid the problems mentioned above?
The "common subexpression elimination" for (the encoding of) r.x + r.x can be done only if OCaml knows the definition of r and inlines it. (Sorry my previous answer was inaccurate here.)

Gentle Intro to Haskell: " .... there is no single type that contains both 2 and 'b'." Can I not make such a type ?

I am currently learning Haskell, so here are a beginner's questions:
What is meant by single type in the text below ?
Is single type a special Haskell term ? Does it mean atomic type here ?
Or does it mean that I can never make a list in Haskell in which I can put both 1 and 'c' ?
I was thinking that a type is a set of values.
So I cannot define a type that contains Chars and Ints ?
What about algebraic data types ?
Something like: data IntOrChar = In Int | Ch Char ? (I guess that should work but I am confused what the author meant by that sentence.)
Btw, is that the only way to make a list in Haskell in which I can put both Ints and Chars? Or is there a more tricky way ?
A Scala analogy: in Scala it would be possible to write implicit conversions to a type that represents both Ints and Chars (like IntOrChar) and then it would be possible to put seemlessly Ints and Chars into List[IntOrChar], is that not possible with Haskell ? Do I always have to explicitly wrap every Int or Char into IntOrChar if I want to put them into a list of IntOrChar ?
From Gentle Intro to Haskell:
Haskell also incorporates polymorphic types---types that are
universally quantified in some way over all types. Polymorphic type
expressions essentially describe families of types. For example,
(forall a)[a] is the family of types consisting of, for every type a,
the type of lists of a. Lists of integers (e.g. [1,2,3]), lists of
characters (['a','b','c']), even lists of lists of integers, etc., are
all members of this family. (Note, however, that [2,'b'] is not a
valid example, since there is no single type that contains both 2 and
'b'.)
Short answer.
In Haskell there are no implicit conversions. Also there are no union types - only disjoint unions(which are algebraic data types). So you can only write:
someList :: [IntOrChar]
someList = [In 1, Ch 'c']
Longer and certainly not gentle answer.
Note: This is a technique that's very rarely used. If you need it you're probably overcomplicating your API.
There are however existential types.
{-# LANGUAGE ExistentialQuantification, RankNTypes #-}
class IntOrChar a where
intOrChar :: a -> Either Int Char
instance IntOrChar Int where
intOrChar = Left
instance IntOrChar Char where
intOrChar = Right
data List = Nil
| forall a. (IntOrChar a) => Cons a List
someList :: List
someList = (1 :: Int) `Cons` ('c' `Cons` Nil)
Here I have created a typeclass IntOrChar with only function intOrChar. This way you can convert anything of type forall a. (IntOrChar a) => a to Either Int Char.
And also a special kind of list that uses existential type in its second constructor.
Here type variable a is bound(with forall) at the constructor scope. Therefore every time
you use Cons you can pass anything of type forall a. (IntOrChar a) => a as a first argument. Consequently during a destruction(i.e. pattern matching) the first argument will
still be forall a. (IntOrChar a) => a. The only thing you can do with it is either pass it on or call intOrChar on it and convert it to Either Int Char.
withHead :: (forall a. (IntOrChar a) => a -> b) -> List -> Maybe b
withHead f Nil = Nothing
withHead f (Cons x _) = Just (f x)
intOrCharToString :: (IntOrChar a) => a -> String
intOrCharToString x =
case intOrChar of
Left i -> show i
Right c -> show c
someListHeadString :: Maybe String
someListHeadString = withHead intOrCharToString someList
Again note that you cannot write
{- Wont compile
safeHead :: IntOrChar a => List -> Maybe a
safeHead Nil = Nothing
safeHead (Cons x _) = Just x
-}
-- This will
safeHead2 :: List -> Maybe (Either Int Char)
safeHead2 Nil = Nothing
safeHead2 (Cons x _) = Just (intOrChar x)
safeHead will not work because you want a type of IntOrChar a => Maybe a with a bound at safeHead scope and Just x will have a type of IntOrChar a1 => Maybe a1 with a1 bound at Cons scope.
In Scala there are types that include both Int and Char such as AnyVal and Any, which are both supertypes of Char and Int. In Haskell there is no such hierarchy, and all the basic types are disjoint.
You can create your own union types which describe the concept of 'either an Int or a Char (or you could use the built-in Either type), but there are no implicit conversions in Haskell to transparently convert an Int into an IntOrChar.
You could emulate the concept of 'Any' using existential types:
data AnyBox = forall a. (Show a, Hashable a) => AB a
heteroList :: [AnyBox]
heteroList = [AB (1::Int), AB 'b']
showWithHash :: AnyBox -> String
showWithHash (AB v) = show v ++ " - " ++ (show . hash) v
let strs = map showWithHash heteroList
Be aware that this pattern is discouraged however.
I think that the distinction that is being made here is that your algebraic data type IntOrChar is a "tagged union" - that is, when you have a value of type IntOrChar you will know if it is an Int or a Char.
By comparison consider this anonymous union definition (in C):
typedef union { char c; int i; } intorchar;
If you are given a value of type intorchar you don't know (apriori) which selector is valid. That's why most of the time the union constructor is used in conjunction with a struct to form a tagged-union construction:
typedef struct {
int tag;
union { char c; int i; } intorchar_u
} IntOrChar;
Here the tag field encodes which selector of the union is valid.
The other major use of the union constructor is to overlay two structures to get an efficient mapping between sub-structures. For example, this union is one way to efficiently access the individual bytes of a int (assuming 8-bit chars and 32-bit ints):
union { char b[4]; int i }
Now, to illustrate the main difference between "tagged unions" and "anonymous unions" consider how you go about defining a function on these types.
To define a function on an IntOrChar value (the tagged union) I claim you need to supply two functions - one which takes an Int (in the case that the value is an Int) and one which takes a Char (in case the value is a Char). Since the value is tagged with its type, it knows which of the two functions it should use.
If we let F(a,b) denote the set of functions from type a to type b, we have:
F(IntOrChar,b) = F(Int,b) \times F(Char,b)
where \times denotes the cross product.
As for the anonymous union intorchar, since a value doesn't encode anything bout its type the only functions which can be applied are those which are valid for both Int and Char values, i.e.:
F(intorchar,b) = F(Int,b) \cap F(Char,b)
where \cap denotes intersection.
In Haskell there is only one function (to my knowledge) which can be applied to both integers and chars, namely the identity function. So there's not much you could do with a list like [2, 'b'] in Haskell. In other languages this intersection may not be empty, and then constructions like this make more sense.
To summarize, you can have integers and characters in the same list if you create a tagged-union, and in that case you have to tag each of the values which will make you list look like:
[ I 2, C 'b', ... ]
If you don't tag your values then you are creating something akin to an anonymous union, but since there aren't any (useful) functions which can be applied to both integers and chars there's not really anything you can do with that kind of union.

Convert datatype to string (SML)

I have a function that returns a (char * int) list list, like [[(#"D", 3)], [(#"F", 7)]], and now I'm wondering if it's posssible to convert this to a string, so that I can use I/O and read it to another file?
First of all, I assume you meant a value like [[(#"D", 3)], [(#"F", 7)]] (note the extra parens) since SML requires parentheses around tuple construction. OCaml uses a slightly different syntax, and allows just commas, like a, b, to construct tuples. I mention this because what follows is totally specific to Standard ML, and doesn't apply to OCaml, because I believe that in OCaml your best bet is an entirely different approach, which I don't know much about (macros, i.e. ocamlp4/5). So I assume that was just a typo and that you're interested in Standard ML.
Now, unfortunately there is no general toString function in Standard ML. Something like that would have to have some kind special support in the language and implementation, since it's not possible to write a function with the type 'a -> string. You basically have to write your own toString : t -> string for each type t.
As you can imagine, this gets tedious fast. I've spent a little time researching the options (for this and other boilerplate functions like compare : 't * 't -> order) and there is one very interesting technique outlined in the paper "Generics for the working ML'er" (http://dl.acm.org/citation.cfm?id=1292547) but it's pretty advanced and I could never actually get the code to compile (that said the paper is very interesting) The full generics library described in that paper is in the MLton lib repo (https://github.com/MLton/mltonlib/tree/master/com/ssh/generic/unstable). Maybe you'll have better luck?
Here's a slightly lighter weight approach that is less powerful but easier to understand, IMHO. I wrote this after reading that paper and struggling to get it to work. The idea is to write building blocks for toString functions (called show in this case) and compose them with other functions for your own types.
structure Show =
struct
(* Show.t is the type of toString functions *)
type 'a t = 'a -> string
val int: int t = Int.toString
val char: char t = Char.toString
val list: 'a t -> 'a list t =
fn show => fn xs => "[" ^ concat (ExtList.interleave (map show xs) ",") ^ "]"
val pair: 'a t * 'b t -> ('a * 'b) t =
fn (showa,showb) => fn (a,b) => "(" ^ showa a ^ "," ^ showb b ^ ")"
(* ... *)
end
Since your type doesn't actually have any user defined datatypes, it's very easy to write the toString function using this structure:
local
open Show
in
val show : (char * int) list list -> string = list (list (pair (char, int)))
end
- show [[(#"D", 3)], [(#"F", 7)]] ;
val it = "[[(D,3)],[(F,7)]]" : string
What I like about this is that the composed functions read like the type turned inside out. It's a quite an elegant style, which I cannot take credit for as I took it from the generics paper linked above.
The rest of the code for Show (and a related module Eq for equality comparison) is here: https://github.com/spacemanaki/lib.sml

Defining a function a -> String, which works for types without Show?

I'd like to define a function which can "show" values of any type, with special behavior for types which actually do define a Show instance:
magicShowCast :: ?
debugShow :: a -> String
debugShow x = case magicShowCast x of
Just x' -> show x'
Nothing -> "<unprintable>"
This would be used to add more detailed information to error messages when something goes wrong:
-- needs to work on non-Showable types
assertEq :: Eq a => a -> a -> IO ()
assertEq x y = when (x /= y)
(throwIO (AssertionFailed (debugShow x) (debugShow y)))
data CanShow = CanShow1
| CanShow 2
deriving (Eq, Show)
data NoShow = NoShow1
| NoShow2
deriving (Eq)
-- AssertionFailed "CanShow1" "CanShow2"
assertEq CanShow1 CanShow2
-- AssertionFailed "<unprintable>" "<unprintable>"
assertEq NoShow1 NoShow2
Is there any way to do this? I tried using various combinations of GADTs, existential types, and template haskell, but either these aren't enough or I can't figure out how to apply them properly.
The real answer: You can't. Haskell intentionally doesn't define a generic "serialize to string" function, and being able to do so without some type class constraint would violate parametricity all over town. Dreadful, just dreadful.
If you don't see why this poses a problem, consider the following type signature:
something :: (a, a) -> b -> a
How would you implement this function? The generic type means it has to be either const . fst or const . snd, right? Hmm.
something (x,y) z = if debugShow z == debugShow y then y else x
> something ('a', 'b') ()
'a'
> something ('a', 'b') 'b'
'b'
Oooooooops! So much for being able to reason about your program in any sane way. That's it, show's over, go home, it was fun while it lasted.
The terrible, no good, unwise answer: Sure, if you don't mind shamelessly cheating. Did I mention that example above was an actual GHCi session? Ha, ha.
import Control.Exception
import Control.Monad
import GHC.Vacuum
debugShow :: a -> String
debugShow = show . nameGraph . vacuumLazy
assertEq :: Eq a => a -> a -> IO ()
assertEq x y = when (x /= y) . throwIO . AssertionFailed $
unlines ["assertEq failed:", '\t':debugShow x, "=/=", '\t':debugShow y]
data NoShow = NoShow1
| NoShow2
deriving (Eq)
> assertEq NoShow1 NoShow2
*** Exception: assertEq failed:
[("|0",["NoShow1|1"]),("NoShow1|1",[])]
=/=
[("|0",["NoShow2|1"]),("NoShow2|1",[])]
Oh. Ok. That looks like a fantastic idea, doesn't it.
Anyway, this doesn't quite give you what you want, since there's no obvious way to fall back to a proper Show instance when available. On the other hand, this lets you do a lot more than show can do, so perhaps it's a wash.
Seriously, though. Don't do this in actual, working code. Ok, error reporting, debugging, logging... that makes sense. But otherwise, it's probably very ill-advised.
I asked this question a while ago on the haskell-cafe list, and the experts said no. Here are some good responses,
http://www.haskell.org/pipermail/haskell-cafe/2011-May/091744.html
http://www.haskell.org/pipermail/haskell-cafe/2011-May/091746.html
The second one mentions GHC advanced overlap, but my experience was that it doesn't really work.
For your particular problem, I'd introduce a typeclass
class MaybeShow a where mshow :: a -> String
make anything that is showable do the logical thing
instance Show a => MaybeShow a where mshow = show
and then, if you have a fixed number of types which wouldn't be showable, say
instance MaybeShow NotShowableA where mshow _ = "<unprintable>"
of course you could abstract it a little,
class NotShowable a
instance NotShowable a => MaybeShow a where mshow _ = "<unprintable>"
instance NotShowable NotShowableA -- etc.
You shouldn't be able to. The simplest way to implement type classes is by having them compile into an extra parameter
foo :: Show s => a -> s
turns into
foo :: show -> a -> s
The program just passess around the type class instances (like v-tables in C++) as ordinary data. This is why you can trivially use things that look not just like multiple dispatch in OO languages, but can dispatch off the return type.
The problem is that a signature
foo :: a -> String
has no way of getting the implementation of Show that goes for a in cases when it has one.
You might be able to get something like this to work in particular implementations, with the correct language extensions (overlapping instance, etc) on, but I havent tried it
class MyShow a where
myShow :: a -> String
instance (Show a) => MyShow a where
myShow = show
instance MyShow a where
myShow = ...
one trick that might help is enable type families. It can let you write code like
instance (a' ~ a, Show a') => MyShow a
which can sometimes help you get code past the compiler that it doesn't think looks okay.