Modeling exchange in Haskell - haskell

I'm new to Haskell, and I'm looking to model stock exchange library. It's meant to be a library, hence specifics to be defined by the user. The way I intend to use this is to have users define things like this.
data MyExchange = MyExchange { name :: ExchangeName
, base :: Currency
, quote :: Currency }
deriving (Eq, Show)
instance Exchange MyExchange
data MyExchangeBookMessage =
MyExchangeBookMessage { time :: Time
, exchange :: MyExchange
, price :: Price
, side :: Side
, amount :: Maybe Amount }
deriving (Eq, Show)
instance ExchangeBookMessage MyExchangeBookMessage
I've tried the following, but immediately ran into some limitations of type classes. Below is the code and the error message. Specifically what are the alternatives to parameterizing type classes with multiple types?
Here is the code for the library
module Lib where
data Side = Buy | Sell deriving (Eq, Show)
newtype Amount = Amount Rational deriving (Eq, Show)
newtype Price = Price Rational deriving (Eq, Show)
newtype Currency = Currency String deriving (Eq, Show)
newtype Time = Time Integer deriving (Eq, Show)
type ExchangeName = String
class Exchange a where
name :: a -> ExchangeName
base :: a -> Currency
quote :: a -> Currency
class Message a where
time :: a -> Time
class (Message a, Exchange e) => ExchangeMessage a e where
exchange :: a -> e
class ExchangeMessage a b => BookMessage a b where
price :: a -> Price
side :: a -> Side
amount :: a -> Maybe Amount
And the error message:
src/Lib.hs:22:1: error:
• Too many parameters for class ‘ExchangeMessage’
(Use MultiParamTypeClasses to allow multi-parameter classes)
• In the class declaration for ‘ExchangeMessage’
Later I would like to be able to implement type classes like this:
class Strategy s where
run (Message m, Action a) => s -> m -> a
In the Strategy implementations the run function will take an abstract message m, pattern match it against relevant Message data constructors and return specific action.
I'm porting some Scala code. in Scala I was using a hierarchy of traits with concrete case classes at the bottom:
trait Exchange {
def name: String
def base: Currency
def quote: Currency
}
case class MyExchange(base: Currency, quote: Currency) {
val name = "my-exchange"
}
trait Message {
def time: Long
}
trait ExchangeMessage extends Message {
def exchange: Exchange
}
trait BookMessage extends ExchangeMessage {
def price: Double
def side: Side
def amount: Option[Double]
}
case class MyBookMessage(time: Long, price: Double, side: Side, amount: Option[Double]) {
def exchange: Exchange = MyExchange(...)
}

First order of business, take GHC's suggestion and enable MultiParamTypeCLasses at the top of the file.
{-# LANGUAGE MultiParamTypeClasses #-}
This is a very common extension, and it will fix the immediate problem.
However there appear to be some modeling issues and if you proceed with this design you will surely hit some problems you didn't expect. I can go into all the details of what your code means, but I'm not sure that would be very helpful. Instead I'll just point you in the right direction, I think, which is to use data records instead of typeclasses. Haskell typeclasses do not correspond to classes in other OO langauges and it confuses many beginners. But I think you want to model it like this:
data Exchange = Exchange
{ name :: ExchangeName
, base :: Currency
, quote :: Currency
}
data Message = Message
{ time :: Time }
-- etc.
which will simplify everything for you, and this acts more like OO classes than your model. Keep in mind that records can have functions and other complex data structures as fields, which is how you get the analog of virtual methods, for example:
data MessageLogger = MessageLogger
{ log :: String -> IO () }

First of all, you will probably not be able to write a class instance for ExchangeMessage. The reason is that the exchange function must be able to return any type e. If you want to keep this way, you will need to provide a way to build an arbitrary exchange!
class Exchange a where
name :: a -> ExchangeName
base :: a -> Currency
quote :: a -> Currency
build :: Time -> a
This is the only possible signature for build, as all you can know from an exchange is that it has a Time you can query, and it's probably useless.
What I would think is a better design is to have concrete types for all those classes you defined. For example:
data Exchange = Exchange { getName :: ExchangeName
, getBase :: Currency
, getQuote :: Currency
} deriving (Show, Eq)
Then, once you have written the functions that work with these concrete types, you can either:
write functionsof type MyExchange -> Exchange for example, to adapt functions expecting an Exchange
use classy lenses, so as to directly write functions that will consume abitrary types
All in all, for that kind of applications, if you want to be fancy with types I would suggest to use phantom types for your currencies, so that you'll statically enforce for example you can only compute the sum of two amounts of money using the same currency. Using typeclasses to mimic the habits of OO will not produce APIs that are nice to use or code that is clear.

Related

Is there an idiomatic way to do deal with this situation when two structures share some content?

I'm making a toy forum to gain familiarity with Haskell and Servant.
My API looks something like this:
type UserAPI = "messages" :> ReqBody '[JSON] Msg :> Header "X-Real-IP" String :> Post '[JSON] APIMessage
:<|> "messages" :> ReqBody '[JSON] Int :> Get '[JSON] [Msg']
My types look something like this:
data Msg = Msg
{ thread :: Int
, dname :: String
, contents :: String
} deriving (Eq, Show, Generic)
data Msg' = Msg'
{ thread' :: Int
, stamp' :: UTCTime
, dname' :: String
, contents' :: String
, ip' :: String
} deriving (Eq, Show, Generic)
and they derive ToJSON / FromJSON / FromRow instances, which is very convenient.
Msg represents the data the API expects when receiving messages and Msg' the data it sends when queried for messages, which has two additional fields that are added by the server, but this doesn't feel right and there has to be a cleaner way to achieve this.
Any insight on an idiomatic way to do deal with this sort of problem appreciated.
I will consider here that you question is more a conceptual one ("What can I do when I have two data types that share some structure ?") than a simple "How do I model inheritance in Haskell ?" that is already replied here.
To answer your question, you will need to consider more than just the structure of your data. For example, if I provide you A and B and if I state that
data A = A Int String
data B = B Int
I doubt that you will automatically make the assumption that a A is a B with an extra String. You will probably try to figure the exact relation between these two data structure. And this is the good thing to do.
If each instance of A can actually be seen as an instance of B then it can be relevant to provide way to represent it in your code. Then you could use a plain Haskell way with a
data A = A { super :: B, theString :: String }
data B = B { id :: Int }
Obviously, this will not be easy to work with these datatype without creating some other functions. For example a fromB function could be relevant
fromB :: B -> String -> A
toB :: A -> B
And you can also use typeclass to access id
class HasId a where
getId :: a -> Int
instance HasId A where
getId = id . super
This is where some help form Lens can be useful. And the answer to this question How do I model inheritance in Haskell? is a good start. Lens package provides Object Oriented syntactic sugar to handle inheritance relationship.
However you can also find that a A is not exactly a B but they both share the same ancestor. And you could prefer to create something like
data A = A { share :: C, theString :: String }
data B = B { share :: C }
data C = C Int
This is the case when you do not want to use a A as a B, but it exists some function that can be used by both. The implementation will be near the previous cases, so I do not explain it.
Finally you could find that there does not really exists relation that can be useful (and, therefore, no function that will really exists that is shared between A and B). Then you would prefer to keep your code.
In your specific case, I think that there is not a direct "is a" relation between Msg and Msg' since one is for the receiving and the other is for the sending. But they could share a common ancestor since both are messages. So they will probably have some constructors in common and accessors (in term of OO programming).
Try to never forget that structure is always bind to some functions. And what category theory teaches us is that you cannot only look at the structures only but you have to consider their functions also to see the relation between each other.

How can I concisely represent a heterogenous sum type in Haskell?

I'm writing a program that transcodes financial statements into a ledger. In that program I have types representing different activities:
data Withdrawal = Withdrawal { wTarget :: !Text, wAmount :: !Cash, wBalance :: !Cash }
data Fee = { fFee :: !Cash, fBalance :: !Cash }
-- many more
I use those types, because I have functions that are transaction-type specific.
I also wanted to write an activity parser that translates CSV records into those types, so I created an Activity sum type:
data Activity =
ActivityFee Fee
| ActivityWithdrawal Withdrawal
| -- ...
parseActivity :: CsvRecord -> Activity
That Activity is quite boilerplate'y. Having to have a new Activity* constructor for a new activity type is slightly cumbersome.
Is there a more idiomatic or better design pattern for this problem? Was it C++, std::variant would be convenient, because adding a new activity type wouldn't entail adding a new boilerplate constructor.
I've considered type-classes, but the problem with them is that they are not closed and I can't pattern match to create a function like applyActivity :: Activity -> Wallet -> Wallet. I see that I could make applyActivity into a function of an Activity class, but then problem is that this solution is only straightforward if only one argument is using this pattern. If we had two arguments like foo :: (ClassOne a, ClassTwo b) => a -> b -> c, then it's not clear to which class foo should belong.
One option is not bothering to define the sum type, and instead make parseActivity return the Wallet -> Wallet operation that characterizes activities, wrapped in some Parser type with an Alternative instance.
parseActivity :: CsvRecord -> Parser (Wallet -> Wallet)
You would still need to define a big Parser value using a bunch of <|> that composed the Parsers for each possible activity.
Additional operations other than Wallet -> Wallet could be supported by making the parser return a record of functions:
data ActivityOps = ActivityOps {
applyActivity :: Wallet -> Wallet,
debugActivity :: String
}
This is still not as versatile as the sum type, because it constrains beforehand the operations that we might do with the activity. To support a new operation, we would need to change the Parser ActivityOps value. With the sum type, we would simply define a new function.
A variant of this solution would be to define a typeclass like
class ActivityOps a where
applyActivity :: a -> Wallet -> Wallet
debugActivity :: a -> String
And make the Parser return some kind of existential like:
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTSyntax #-}
data Activity where
MakeActivity :: ActivityOps a => a -> Activity
This is sometimes frowned upon, but it would have the benefit of being able to easily invoke ActivityOps methods on activities of known type.
Extensible sums are a possible alternative. In that case one would write
type Activity = Sum '[Fee, Withdrawal]
and use match (\fee -> ...) (\withdrawal -> ...) as a substitute for pattern matching.

Generic type for OO classes in Haskell

I want to have a generic type that can represent any class in a simple class diagram. In this case a class contains:
A name
Any number of arguments of any type
Any number of functions that takes any number of arguments of any type
I have only used simple ADT declarations which is not working in this case, for example this is what I have been stuck with but it gives me no where near the type of flexibility I'm after:
data Attr a = Attr { name :: String
, kind :: a}
deriving (Show)
data Action = Action { name1 :: String
, params :: [Attr Int]}
deriving (Show)
data Class a = NewC { name2 :: String
, attrs :: [Attr Int]
, actions :: [Action]}
deriving (Show)
So my question is now how would I go about representing any arbitrary class in Haskell?
I do not want to do OOP in haskell. Imaging that the class type I'm trying to make will be a node in a graph. However each node in the graph will be a different class.
I think you want to represent your class diagrams entirely as values rather than a mix of values and types. Instead of Attr Int, for example, you might use something like Attr { name="Int", kind=PrimitiveInt }. I've introduced an OopType type below.
data Attr = Attr { name :: String
, kind :: OopType}
deriving (Show)
data Action = Action { name1 :: String
, params :: [Attr]}
deriving (Show)
data Class = NewC { name2 :: String
, attrs :: [Attr]
, actions :: [Action]}
deriving (Show)
data OopType = ClassType Class
| InterfaceType Class -- TODO make a dedicated interface type
| Enum -- TODO make a dedicated enum type
| PrimitiveString
| PrimitiveInt
Note that this representation doesn't model 'generics' (that is, classes that are parameterised by types). To do that, you'd add another field to the Class type.

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?

What's the recommended way of handling complexly composed POD(plain-old-data in OO) in Haskell?

I'm a Haskell newbie.
In statically typed OO languages (for instance, Java), all complex data structures are presented as class and instances. An object can have many attributes (fields). And another object can be a value of the field. Those fields can be accessed with their names, and statically typed by class. Finally, those objects construct huge graph of object which linked each other. Most program uses data graph like this.
How can I archive these functionality in Haskell?
If you really do have data without behavior, this maps nicely to a Haskell record:
data Person = Person { name :: String
, address :: String }
deriving (Eq, Read, Show)
data Department = Management | Accounting | IT | Programming
deriving (Eq, Read, Show)
data Employee = Employee { identity :: Person
, idNumber :: Int
, department :: Department }
| Contractor { identity :: Person
, company :: String }
deriving (Eq, Read, Show)
This says that a Person is a Person who has a name and address (both Strings); a Department is either Management, Accounting, IT, or Programming; and an Employee is either an Employee who has an identity (a Person), an idNumber (an Int), and a department (a Department), or is a Contractor who has an identity (a Person) and a company (a String). The deriving (Eq, Read, Show) lines enable you to compare these objects for equality, read them in, and convert them to strings.
In general, a Haskell data type is a combination of unions (also called sums) and tuples (also called products).1 The |s denote choice (a union): an Employee is either an Employee or a Contractor, a Department is one of four things, etc. In general, tuples are written something like the following:
data Process = Process String Int
This says that Process (in addition to being a type name) is a data constructor with type String -> Int -> Process. Thus, for instance, Process "init" 1, or Process "ls" 57300. A Process has to have both a String and an Int to exist. The record notation used above is just syntactic sugar for these products; I could also have written data Person = Person String String, and then defined
name :: Person -> String
name (Person n _) = n
address :: Person -> String
address (Person _ a) = a
Record notation, however, can be nice for complex data structures.
Also note that you can parametrize a Haskell type over other types; for instance, a three-dimensional point could be data Point3 a = Point3 a a a. This means that Point3 :: a -> a -> a -> Point3 a, so that one could write Point3 (3 :: Int) (4 :: Int) (5 :: Int) to get a Point3 Int, or Point3 (1.1 :: Double) (2.2 :: Double) (3.3 :: Double) to get a Point3 Double. (Or Point3 1 2 3 to get a Num a => Point3 a, if you've seen type classes and overloaded numeric literals.)
This is what you need to represent a data graph. However, take note: one problem for people transitioning from imperative languages to functional ones—or, really, between any two different paradigms (C to Python, Prolog to Ruby, Erlang to Java, whatever)—is to continue to try to solve problems the old way. The solution you're trying to model may not be constructed in a way amenable to easy functional programming techniques, even if the problem is. For instance, in Haskell, thinking about types is very important, in a way that's different from, say, Java. At the same time, implementing behaviors for those types is done very differently: higher-order functions capture some of the abstractions you've seen in Java, but also some which aren't easily expressible (map :: (a -> b) -> [a] -> [b], filter :: (a -> Bool) -> [a] -> [a], and foldr :: (a -> b -> b) -> b -> [a] -> b come to mind). So keep your options open, and consider addressing your problems in a functional way. Of course, maybe you are, in which case, full steam ahead. But do keep this in mind as you explore a new language. And have fun :-)
1: And recursion: you can represent a binary tree, for instance, with data Tree a = Leaf a | Branch a (Tree a) (Tree a).
Haskell has algebraic data types, which can describe structures or unions of structures such that something of a given type can hold one of a number of different sets of fields. These fields can set and accessed both positionally or via names with record syntax.
See here: http://learnyouahaskell.com/making-our-own-types-and-typeclasses

Resources