In this week’s lab, we’re going to look at how you do a redesign in the
functional paradigm. This is actually one of the unsung superpowers of a
language like Haskell — if you want to change one of the basic conceits of your
Copyright By PowCoder代写 加微信 powcoder
app, you can use the compiler to help you identify all the changes that have to
be made quickly, giving you confidence that you’ve covered everything. and have argued that writing good code boils down to one thing:
good code is easy to change. So in this lab, let’s take a look at how you change
your code in Haskell.
No need to create a new stack project for this; just copy your
functional-adventure stack project over from last week and use that.
## 1.1 Out with the type alias, in with the datatype
Whenever you’re trying to use algebraic datatypes to model the possible states
your app can or can’t be in, you’re faced with a decision. How detailed do you
want to get? Should such and such code be a string, or should it be a special
code datatype in the same genre as the phone numbers from the second week of
this class? At some point, you’re typically going to have to stop defining your
own types and start deciding that such and such is going to be an integer, or a
string, or a float, or some other primitive.
The design we’ve been working with ‘bottoms out’ at item names and room names,
which we just encoded as strings. In principle, that’s problematic, because
there are plenty of strings that don’t correspond to the names of any items or
rooms in the game. So to lower the likelihood that at some point in the
development process, you’re going to use a string not corresponding to an item
as an item name (or similarly for room names), let’s go ahead and change item
names and room names into their own real datatype.
In `src/Item.hs`, change `ItemName` from a type alias into the following
“`haskell
data ItemName
| Tarragon
deriving (Show, Eq, Ord)
Next, make sure your type alias for Universe in `src/Item.hs` now has item names
for `Map` keys, rather than strings:
“`haskell
type Universe = M.Map ItemName Item
Now jump into your UNIX shell and run stack build in the root directory of your
functional-adventure stack project. That will do a full compile. What’s that?
You’re getting some new type errors? You bet you are!
### 1.1.1 Exercise: Fix All Values Involving Item Names
If my calculations are correct, assuming you followed the spec laid out in
previous assignments, the first type error you should be getting is in pot, in
the `Item` module (this won’t necessarily be the case — it’ll depend on the
order you wrote everything in — but if you followed the order laid out in the
assignment, I think this’ll be the first). The line number will probably be
different—but the type error should be pretty similar:
• Couldn’t match expected type ‘ItemName’ with actual type ‘[Char]’
• In the first argument of ‘Item’, namely ‘”pot”’
In the expression: Item “pot” 5
In an equation for ‘pot’: pot = Item “pot” 5
24 | pot = Item “pot” 5
| ^^^^^
See? The compiler jumped you straight to the next place in your code that
assumes that an `ItemName` is a string.
The fix here is straightforward: change “pot” to `Pot`. After you fix that type
error, you’ll probably get essentially the same error in jug. You can go ahead
and fix that in the same way.
For this exercise, go ahead and keep fixing whatever type error the compiler
tells you to fix, each time running stack build to jump to you the next place in
your code that will need to be changed. If you’re in an editor with IDE-like
capabilities, you should be able to get it to just automatically move you right
to where the next error is in any file within your project. If not, you can do
it the old fashioned way by looking at the compiler output.
This will vary a little bit from project to project, but you should have to make
somewhere in the ballpark of about 20-25 changes to your code to get it to
compile again, in light of the redefinition of `ItemName` from a type alias to an
honest-to-god datatype.
Hot tip: there will be some places in your code—like the messages associated
with the checks on taking and dropping—where you should be able to easily fix
the compiler error by just changing an `iname` to a `show . iname`, or something
similar. You’ll be writing a real `Show` instance for item names in just a sec,
but for now, just use the one we automatically derived.
## 1.2 Once Again, for Room Names
Next, we’ll do the same with room names. In `src/Room.hs`, change your
`RoomName` type alias to the following datatype:
“`haskell
data RoomName
| LivingRoom
deriving (Show, Eq, Ord)
Also make sure that your type alias for `GameMap` in `src/GameState.hs` is
defined in terms of your new `RoomName` datatype (it should be already, but no
harm in double-checking):
“`haskell
type GameMap = M.Map RoomName Room
### 1.2.1 Exercise: Fix All Values Involving Room Names
Then, as before, run stack build to find out the next place in your code that
needs to be updated. The changes you have to make should all be pretty
straightforward; the type error will say a `RoomName` is expected where instead
you gave it a string.
As before, keep recompiling, fixing type errors as you go, until your
functional-adventure project compiles. Exactly how many changes you have to make
will vary from case to case, but it should be somewhere around 15-20.
### 1.2.2 Exercise: Show instance for Item Names
Finally, let’s fix our `Show` instances. Remove `Show` from your `ItemName`
`deriving` clause and write your own `Show` instance for item names that
displays them as the strings we were using before:
“`haskell
λ> Tarragon
### 1.2.3 Exercise: Show instance for room names
Remove `Show` from your `RoomName` `deriving` clause and write your own `Show`
instance for room names that displays them as the strings we were using before:
“`haskell
λ> Bedroom
λ> LivingRoom
living room
Boom. That’s how you do a redesign in Haskell. Thanks to the type system, you
can sleep easy at night knowing the compiler showed you every part of the code
you broke when you redefined these datatypes—and that therefore, you updated
every part that needed updating.
程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com