What is the right way to declare data that is an extension of another data - haskell

I am modelling a set of "things". For the most part all the things have the same characteristics.
data Thing = Thing { chOne :: Int, chTwo :: Int }
There is a small subset of things that can be considered to have an "extended" set of characteristics in addition to the base set shared by all members.
chThree :: String
I'd like to have functions that can operate on both kinds of things (these functions only care about properties chOne and chTwo):
foo :: Thing -> Int
I'd also like to have functions that operate on the kind of things with the chThree characteristic.
bar :: ThingLike -> String
I could do
data ThingBase = Thing { chOne :: Int, chTwo :: Int }
data ThingExt = Thing { chOne :: Int, chTwo :: Int, chThree :: Int }
fooBase :: ThingBase -> Int
fooExt :: ThingExt -> Int
bar :: ThingExt -> String
But this is hideous.
I guess I could use type classes, but all the boilerplate suggests this is wrong:
class ThingBaseClass a of
chOne' :: Int
chTwo' :: Int
instance ThingBaseClass ThingBase where
chOne' = chOne
chTwo' = chTwo
instance ThingBaseClass ThingExt where
chOne' = chOne
chTwo' = chTwo
class ThingExtClass a of
chThree' :: String
instance ThingExtClass ThingExt where
chThree' = chThree
foo :: ThingBaseClass a => a -> Int
bar :: ThingExtClass a => a -> String
What is the right way to do this?

One way to do so, is the equivalent of OO aggregation :
data ThingExt = ThingExt { thing :: Thing, chTree :: Int }
You can then create a class as in your post
instance ThingLike ThingExt where
chOne' = chOne . thing
chTwo' = chTwo . thing
If you are using the lens library you can use makeClassy which will generate all this boiler plate for you.

You can make a data type that is a type union of the two distinct types of things:
data ThingBase = ThingBase { chBaseOne :: Int, chBaseTwo :: Int }
data ThingExt = ThingExt { chExtOne :: Int, chExtTwo :: Int, chExtThree :: Int }
data ThingLike = CreatedWithBase ThingBase |
CreatedWithExt ThingExt
Then for any function which should take either a ThingBase or a ThingExt, and do different things depending, you can do pattern matching on the type constructor:
foo :: ThingLike -> Int
foo (CreatedWithBase (ThingBase c1 c2)) = c1 + c2
foo (CreatedWithExt (ThingExt c1 c2 c3)) = c3
-- Or another way:
bar :: ThingLike -> Int
bar (CreatedWithBase v) = (chBaseOne v) + (chBaseTwo v)
bar (CreatedWithExt v) = chExtThree v
This has the benefit that it forces you to pedantically specify exactly what happens to ThingBases or ThingExts wherever they appear to be processed as part of handling a ThingLike, by creating the extra wrapping layer of constructors (the CreatedWithBase and CreatedWithExt constructors I used, whose sole purpose is to indicate which type of thing you expect at a certain point of code).
But it has the disadvantage that it doesn't allow for overloaded names for the field accessor functions. Personally I don't see this as too big of a loss, since the extra verbosity required to reference attributes acts like a natural complexity penalty and helps motivate the programmer to keep the code sparse and use fewer bad accessor/getter/setter anti-patterns. However, if you want to go far with overloaded accessor names, you should look into lenses.
This is just one idea and it's not right for every problem. The example you already give with type classes is also perfectly fine and I don't see any good reason to call it hideous.
Just about the only "bad" thing would be wanting to somehow implicitly process ThingBases differently from ThingExts without needing anything in the type signature or the pattern matching sections of a function body to explicitly tell people reading your code precisely when and where the two different types are differentiated, which would be more like a duck typing approach which is not really what you should do in Haskell.
This seems to be what you're trying to get at by trying to force both ThingBase and ThingExt to have a value constructor with the same name of just Thing -- it seems artificially nice that the same word can construct values of either type, but my feeling is it's not actually nice. I might be misunderstanding though.

A very simple solution is to introduce a type parameter:
data ThingLike a = ThingLike { chOne, chTwo :: Int, chThree :: a }
deriving Show
Then, a ThingBase is just a ThingLike with no third element, so
type ThingBase = ThingLike ()
ThingExt contains an additional Int, so
type ThingExt = ThingLike Int
This has the advantage of using only a single constructor and only three record accessors. There is minimal duplication, and writing your desired functions is simple:
foo :: ThingLike a -> Int
foo (ThingLike x y _) = x+y
bar :: ThingExt -> String
bar (ThingLike x y z) = show $ x+y+z

One option is:
data Thing = Thing { chOne :: Int, chTwo :: Int }
| OtherThing { chOne :: Int, chTwo :: Int, chThree :: String }
Another is
data Thing = Thing { chOne :: Int, chTwo :: Int, chThree :: Maybe String }
If you want to distinguish the two Things at the type level and have overloaded accessors then you need to make use of a type class.

You could use a Maybe ThingExt field on ThingBase I guess, at least if you only have one extension type.
If you have several extensions like this, you can use a combination of embedding and matching on various constructors of the embedded data type, where each constructor represents one way to extend the base structure.
Once that becomes unmanageable, classes might become unevitable, but some kind of data type composition would still be useful to avoid duplication.

Related

Strict type alias in Haskell

Suppose I have a recursive function taking 3 integers, each having a different meaning, e.g.
func :: Int -> Int -> Int -> SomeType1 -> SomeType2
What I want is to prevent myself from mistyping the order of the arguments like this (somewhere in the func implementation):
func a b c t = f b a c ( someProcessing t )
The easiest way I've come up with is to define type aliases like
type FuncFirstArg = Int
type FuncSecondArg = Int
type FuncThirdArg = Int
And change func signature:
func :: FuncFirstArg -> FuncSecondArg -> FuncThirdArg -> SomeType1 -> SomeType2
But it seems like this approach doesn't work as I intended. Why does Haskell still allow me to pass FuncSecondArg as a first argument and so on. Is there a way to do what I want without declaring datatypes?
type in Haskell is a rename of an existing type. Just like String and [Char] are fully exchangeable, so are FuncFirstArg and Int, and by transition FuncSecondArg as well.
The most normal solution is to use a newtype which was introduced exactly for the purpose of what you try to achieve. For convenience, it is good to declare it as a record:
newtype FuncFirstArg = FuncFirstArg {unFuncFirstArg :: Int}
Note that newtype is entirely reduced during compilation time, so it has no overhead on the runtime.
However, if you have many arguments like in your example, a common strategy is to create a dedicated type for all of the parameters supplied to the function:
data FuncArgs = FuncArgs
{ funcA :: Int
, funcB :: Int
, funcC :: Int
, funcT :: Sometype1
}
f :: FuncArgs -> Sometype2
Yes, it has some bad impact on currying and partial application, but in many cases you can deal with it by providing predefined argument packs or even uncurry the function:
defaultArgs :: Sometype1 -> FuncArgs
defaultArgs t = FuncArgs {a = 0, b = 0, c = 0, t = t}
fUnc :: Int -> Int -> Int -> SomeType1 -> SomeType2
fUnc a b c t = f $ FuncArgs a b c t
Conclusion
For the typechecker to distinguish types, the types have to be actually different. You can't skip defining new types, therefore.

Haskell type with derived value

Is it possible to have a type preform a function one of its value to generate another one of it's values? For instance:
data Foo=Foo {valueOne::Int, valueTwo=valueOne*2} deriving (Bar)
Or am I thinking about this in the wrong way? Any help is appreciated!
If you always want the second field to depend on the first, just write a plain function:
data Foo = Foo { valueOne :: Int } deriving (Bar)
valueTwo :: Foo -> Int
valueTwo x = valueOne x * 2
The only difference is that the Bar instance, which is automatically generated, won't notice the second field.
If, instead, you want to generate values with such constraint, but still be able to sometimes disregard that, use a smart constructor:
data Foo = Foo { valueOne :: Int, valueTwo :: Int } deriving (Bar)
foo :: Int -> Foo
foo x = Foo x (2 * x)
If you use foo instead of Foo to construct new values, you will not need to pass the second argument, which will be derived from the first one.
Usually this is used in a module which does not export the constructor Foo, but exports the smart constructor foo. In this way the users of the module are constrained to build values satisfying the invariant, while the functions in the module can ignore it, when needed.

How to store arbitrary values in a recursive structure or how to build a extensible software architecture?

I'm working on a basic UI toolkit and am trying to figure out the overall architecture.
I am considering to use WAI's structure for extensibility. A reduced example of the core structure for my UI:
run :: Application -> IO ()
type Application = Event -> UI -> (Picture, UI)
type Middleware = Application -> Application
In WAI, arbitrary values for Middleware are saved in the vault. I think that this is a bad hack to save arbitary values, because it isn't transparent, but I can't think of a sufficient simple structure to replace this vault to give every Middleware a place to save arbitrary values.
I considered to recursively store tuples in tuples:
run :: (Application, x) -> IO ()
type Application = Event -> UI -> (Picture, UI)
type Middleware y x = (Application, x) -> (Application, (y,x))
Or to only use lazy lists to provide a level on which is no need to separate values (which provides more freedom, but also has more problems):
run :: Application -> IO ()
type Application = [Event -> UI -> (Picture, UI)]
type Middleware = Application -> Application
Actually, I would use a modified lazy list solution. Which other solutions might work?
Note that:
I prefer not to use lens at all.
I know UI -> (Picture, UI) could be defined as State UI Picture .
I'm not aware of a solution regarding monads, transformers or FRP. It would be great to see one.
Lenses provide a general way to reference data type fields so that you can extend or refactor your data set without breaking backwards compatibility. I'll use the lens-family and lens-family-th libraries to illustrate this, since they are lighter dependencies than lens.
Let's begin with a simple record with two fields:
{-# LANGUAGE Template Haskell #-}
import Lens.Family2
import Lens.Family2.TH
data Example = Example
{ _int :: Int
, _str :: String
}
makeLenses ''Example
-- This creates these lenses:
int :: Lens' Example Int
str :: Lens' Example String
Now you can write Stateful code that references fields of your data structure. You can use Lens.Family2.State.Strict for this purpose:
import Lens.Family2.State.Strict
-- Everything here also works for `StateT Example IO`
example :: State Example Bool
example = do
s <- use str -- Read the `String`
str .= s ++ "!" -- Set the `String`
int += 2 -- Modify the `Int`
zoom int $ do -- This sub-`do` block has type: `State Int Int`
m <- get
return (m + 1)
The key thing to note is that I can update my data type, and the above code will still compile. Add a new field to Example and everything will still work:
data Example = Example
{ _int :: Int
, _str :: String
, _char :: Char
}
makeLenses ''Example
int :: Lens' Example Int
str :: Lens' Example String
char :: Lens' Example Char
However, we can actually go a step further and completely refactor our Example type like this:
data Example = Example
{ _example2 :: Example
, _char :: Char
}
data Example2 = Example2
{ _int2 :: Int
, _str2 :: String
}
makeLenses ''Example
char :: Lens' Example Char
example2 :: Lens' Example Example2
makeLenses ''Example2
int2 :: Lens' Example2 Int
str2 :: Lens' Example2 String
Do we have to break our old code? No! All we have to do is add the following two lenses to support backwards compatibility:
int :: Lens' Example Int
int = example2 . int2
str :: Lens' Example Char
str = example2 . str2
Now all the old code still works without any changes, despite the intrusive refactoring of our Example type.
In fact, this works for more than just records. You can do the exact same thing for sum types, too (a.k.a. algebraic data types or enums). For example, suppose we have this type:
data Example3 = A String | B Int
makeTraversals ''Example3
-- This creates these `Traversals'`:
_A :: Traversal' Example3 String
_B :: Traversal' Example3 Int
Many of the things that we did with sum types can similarly be re-expressed in terms of Traversal's. There's a notable exception of pattern matching: it's actually possible to implement pattern matching with totality checking with Traversals, but it's currently verbose.
However, the same point holds: if you express all your sum type operations in terms of Traversal's, then you can greatly refactor your sum type and just update the appropriate Traversal's to preserve backwards compatibility.
Finally: note that the true analog of sum type constructors are Prisms (which let you build values using the constructors in addition to pattern matching). Those are not supported by the lens-family family of libraries, but they are provided by lens and you can implement them yourself using just a profunctors dependency if you want.
Also, if you're wondering what the lens analog of a newtype is, it's an Iso', and that also minimally requires a profunctors dependency.
Also, everything I've said works for reference multiple fields of recursive types (using Folds). Literally anything you can imagine wanting to reference in a data type in a backwards-compatible way is encompassed by the lens library.

how can I add an unboxed array to a Haskell record?

I want to do write some monte-carlo simulations. Because of the nature of simulation, I'll get much better performance if I use mutable state. I think that unboxed mutable arrays are the way to go. There's a bunch of items I'll want to keep track of, so I've created a record type to hold the state.
import Control.Monad.State
import Data.Array.ST
data Board = Board {
x :: Int
, y :: Int
,board :: STUArray (Int,Int) Int
} deriving Show
b = Board {
x = 5
,y = 5
,board = newArray ((1,1),(10,10)) 37 :: STUArray (Int,Int) Int
}
growBoard :: State Board Int
growBoard = do s <- get
let xo = x s
yo = y s in
put s{x=xo*2, y=yo*2}
return (1)
main = print $ runState growBoard b
If I leave out the "board" field from the record, everything else works fine. But with it, I get a type error:
`STUArray (Int, Int) Int' is not applied to enough type arguments
Expected kind `?', but `STUArray (Int, Int) Int' has kind `* -> *'
In the type `STUArray (Int, Int) Int'
In the definition of data constructor `Board'
In the data type declaration for `Board'
I've read through the Array page, and I can get STUArray examples working. But as soon as I try to add one to my State record, I get the error about the unexpected kind. I'm guessing I need a monad transformer of some kind, but I don't know where to start.
How should I declare an unboxed array inside a record? How should I initialize it?
I see alot of example of unboxed STArray, but they're mostly program fragments, so I feel like I'm missing context.
Also, where can I learn more about "kinds"? I know kinds are "type types" but the abstract nature of that is making it hard to grasp.
STUArray is a mutable array, designed to be used internally from within the ST monad to implement externally-pure code. Just like STRef and all the other structures used in the ST monad, STUArray takes an additional parameter representing a state thread.
The kind error you're getting is simply telling you missed an argument: at the value level, you might get an error "expected b but got a -> b" to tell you you missed an argument; at the type level, it looks like "expected ? but got * -> *", where * represents a plain, "fully-applied" type (like Int). (You can pretend ? is the same as *; it's just there to support unboxed types, which are a GHC-specific implementation detail.)
Basically, you can think of kinds as coming in two shapes:
*, representing a concrete type, like Int, Double, or [(Float, String)];
k -> l, where k and l are both kinds, representing a type constructor, like Tree, [], IO, and STUArray. Such a type constructor takes a type of kind k, and returns a type of kind l.
If you want to use ST arrays, you'll need to add a type parameter to Board:
data Board s = Board {
x :: Int
, y :: Int
,board :: STUArray s (Int,Int) Int
} deriving Show
and use StateT (Board s) (ST s) as your monad rather than just State Board.
However, I don't see any reason to use ST or mutable structures in general here, and I would instead suggest using a simple immutable array, and mutating it in the same way as the rest of your state, with the State monad:
data Board = Board {
x :: Int
, y :: Int
,board :: UArray (Int,Int) Int
} deriving Show
(using Data.Array.Unboxed.UArray)
This can be "modified" just like any other element of your record, by transforming it with the pure functions from the immutable array interface.

Haskell polymorphic functions with records and class types

this post is the following of this one.
I'm realizing a simple battle system as toy project, the typical system you can find in games like Final Fantasy et simila. I've solved the notorious "Namespace Pollution" problem with a class type + custom instances. For example:
type HitPoints = Integer
type ManaPoints = Integer
data Status = Sleep | Poison | .. --Omitted
data Element = Fire | ... --Omitted
class Targetable a where
name :: a -> String
level :: a -> Int
hp :: a -> HitPoints
mp :: a -> ManaPoints
status :: a -> Maybe [Status]
data Monster = Monster{monsterName :: String,
monsterLevel :: Int,
monsterHp :: HitPoints,
monsterMp :: ManaPoints,
monsterElemType :: Maybe Element,
monsterStatus :: Maybe [Status]} deriving (Eq, Read)
instance Targetable Monster where
name = monsterName
level = monsterLevel
hp = monsterHp
mp = monsterMp
status = monsterStatus
data Player = Player{playerName :: String,
playerLevel :: Int,
playerHp :: HitPoints,
playerMp :: ManaPoints,
playerStatus :: Maybe [Status]} deriving (Show, Read)
instance Targetable Player where
name = playerName
level = playerLevel
hp = playerHp
mp = playerMp
status = playerStatus
Now the problem: I have a spell type, and a spell can deal damage or inflict a status (like Poison, Sleep, Confusion, etc):
--Essentially the result of a spell cast
data SpellEffect = Damage HitPoints ManaPoints
| Inflict [Status] deriving (Show)
--Essentially a magic
data Spell = Spell{spellName :: String,
spellCost :: Integer,
spellElem :: Maybe Element,
spellEffect :: SpellEffect} deriving (Show)
--For example
fire = Spell "Fire" 20 (Just Fire) (Damage 100 0)
frogSong = Spell "Frog Song" 30 Nothing (Inflict [Frog, Sleep])
As suggested in the linked topic, I've created a generic "cast" function like this:
--cast function
cast :: (Targetable t) => Spell -> t -> t
cast s t =
case spellEffect s of
Damage hp mana -> t
Inflict statList -> t
As you can see the return type is t, here showed just for consistency. I want be able to return a new targetable (i.e. a Monster or a Player) with some field value altered (for example a new Monster with less hp, or with a new status). The problem is that i can't just to the following:
--cast function
cast :: (Targetable t) => Spell -> t -> t
cast s t =
case spellEffect s of
Damage hp' mana' -> t {hp = hp', mana = mana'}
Inflict statList -> t {status = statList}
because hp, mana and status "are not valid record selector". The problem is that I don't know a priori if t will be a monster or a player, and I don't want to specify "monsterHp" or "playerHp", I want to write a pretty generic function.
I know that Haskell Records are clumsy and not much extensibile...
Any idea?
Bye and happy coding,
Alfredo
Personally, I think hammar is on the right track with pointing out the similarities between Player and Monster. I agree you don't want to make them the same, but consider this: Take the type class you have here...
class Targetable a where
name :: a -> String
level :: a -> Int
hp :: a -> HitPoints
mp :: a -> ManaPoints
status :: a -> Maybe [Status]
...and replace it with a data type:
data Targetable = Targetable { name :: String
, level :: Int
, hp :: HitPoints
, mp :: ManaPoints
, status :: Maybe [Status]
} deriving (Eq, Read, Show)
Then factor out the common fields from Player and Monster:
data Monster = Monster { monsterTarget :: Targetable
, monsterElemType :: Maybe Element,
} deriving (Eq, Read, Show)
data Player = Player { playerTarget :: Targetable } deriving (Eq, Read, Show)
Depending on what you do with these, it might make more sense to turn it inside-out instead:
data Targetable a = Targetable { target :: a
, name :: String
-- &c...
}
...and then have Targetable Player and Targetable Monster. The advantage here is that any functions that work with either can take things of type Targetable a--just like functions that would have taken any instance of the Targetable class.
Not only is this approach nearly identical to what you have already, it's also a lot less code, and keeps the types simpler (by not having class constraints everywhere). In fact, the Targetable type above is roughly what GHC creates behind the scenes for the type class.
The biggest downside to this approach is that it makes accessing fields clumsier--either way, some things end up being two layers deep, and extending this approach to more complicated types can nest them deeper still. A lot of what makes this awkward is the fact that field accessors aren't "first class" in the language--you can't pass them around like functions, abstract over them, or anything like that. The most popular solution is to use "lenses", which another answer mentioned already. I've typically used the fclabels package for this, so that's my recommendation.
The factored-out types I suggest, combined with strategic use of lenses, should give you something that's simpler to use than the type class approach, and doesn't pollute the namespace the way having lots of record types does.
I can suggest three possible solutions.
1) Your types are very OO-like, but Haskell can also express "sum" types with parameters:
data Unit = UMon Monster | UPlay Player
cast :: Spell -> Unit -> Unit
cast s t =
case spellEffect s of
Damage hp' mana' -> case t of
UMon m -> UMon (m { monsterHp = monsterHp m - hp', monsterMana = undefined})
UPluy p -> UPlay (p { playerHp = playerHp p - hp'})
Inflict statList -> undefined
Thing that are similar in OO-design often become "sum" types with parameters in Haskell.
2) You can do what Carston suggests and add all your methods to type classes.
3) You can change your read-only methods in Targetable to be "lenses" that expose both getting and setting. See the stack overflow discussion. If your type class returned lenses then it would make your spell damage possible to apply.
Why don't you just include functions like
InflicteDamage :: a -> Int -> a
AddStatus :: a -> Status -> a
into your type-class?

Resources