Reputation: 3321
I read this statement in the code provided for a homework:-
newtype STR a = STR (Store -> (Result a, Store))
The above link makes it seem like:
a === (Store -> (Result a, Store))
How can this be a valid statement? Does it mean that a
is a function which takes Store as argument and returns ('the same function wrapped in Result', Store)
?
Upvotes: 0
Views: 344
Reputation: 9817
So for data/newtype definitions the left-hand-side holds a type definition including a name and some type variables, while the right hand side holds a constructor list usually also including names and types. An example is:
data List x = Nil | Cons x (List x)
Notice that Nil
and Cons
are your constructors, x
and List x
are types of arguments to the Cons
constructor, while List
is the name of the type (which has kind * -> *
; it requires a type argument ___ to "fill it in" before it can describe a list of ___s).
Sometimes we want to alias a type. There are two ways to do that. First, type
, which leaves the types commensurate -- so if you write type DirectoryPath = [String]
then when you have a DirectoryPath
you can manipulate it like a list of strings; in particular you might use :
or ++
to append to it; so "apps" : base_directory
would be perfectly legal Haskell.
Sometimes, you just want to clobber these functions with a big warning sign, "don't use this if you don't know what you're doing." For that, you might helpfully write data FilePath = FilePath [String]
. Notice that we are abusing notation a little bit, naming the type the same as the only constructor for that type. Now to do the same thing you would have to write:
case base_directory of FilePath bd -> FilePath $ "apps" : bd
Why might you do this? Well, first off, in the above syntax the directory structure is growing from right-to-left whereas most people write directories left-to-right. Second, you might want appending a .
to be a no-op (i.e. bd ++ []
) and ..
to be a parent-pointer (i.e. tail bd
). You might also have some bizarre conventions (e.g. if the list begins with "" then it's an absolute directory, otherwise it's relative to the present directory) which need to be maintained. Finally, you might want to later shift the code to be Maybe [String]
so that a Nothing
value could represent paths which do crazy things, like /../..
(absolute path two parents above the root).
All of this becomes easier if you can just say:
FilePath xs ./ x
| x == "." = FilePath xs
| x == ".." = FilePath (tail xs)
| otherwise = ...
and then enforce that everywhere else people write base_directory ./ "apps"
.
Another example is newtype SanitizedString = Sanitized String
. Since we didn't use type
we get a compile time label which traces through our code making sure that user-provided strings are properly escaped before, say, they head into the database insert statements or user interface or wherever.
What you're probably using it for here is that you can write a Monad
instance for that type and thereby use it with do
-notation.
IF your code only wraps one existing type, newtype
avoids introducing additional laziness worries and data constructor delays and so forth. Otherwise it is just like data
. So in your code:
newtype STR a = STR (Store -> (Result a, Store))
this is not a type
synonym but more like a data
constructor which ultimately disappears after compilation. A STR a
is an alias for a Store -> (Result a, Store)
which was wrapped in a STR
constructor (so it can't be used as a function directly without a destructuring assignment).
Upvotes: 3
Reputation: 6610
The newtype
definition is a bit confusing, because the symbol STR
is used in two different meanings: namely that of type name (the first occurrence) and that of constructor (the second). Renaming both to something different leads to the equivalent
newtype STRType a = STRConstructor (Store -> (Result a, Store))
In other words, this introduces a type STRType a
which is structurally the same as Store -> (Result a, Store)
(but needs to be wrapped in a STRConstructor
)
I hope your course/book already went into the differences between type
, data
and newtype
; otherwise this is going to remain rather mysterious, I'm afraid...
Upvotes: 9