Haskell 中的建模交流
Modeling exchange in Haskell
我是 Haskell 的新手,我正在寻找证券交易所库模型。它意味着成为一个图书馆,因此具体细节由用户定义。我打算使用它的方式是让用户定义这样的东西。
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
我尝试了以下方法,但立即 运行 进入了 类 类型的某些限制。下面是代码和错误信息。具体来说,用多种类型参数化类型 类 的替代方法是什么?
这是库的代码
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
错误信息:
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’
稍后我希望能够像这样实现 类 类型:
class Strategy s where
run (Message m, Action a) => s -> m -> a
在 Strategy
实现中,run
函数将采用抽象消息 m,将其与相关 Message
数据构造函数和 return 特定操作进行模式匹配。
我正在移植一些 Scala 代码。在 Scala 中,我使用的是具有具体案例 类 底部的特征层次结构:
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(...)
}
首要任务,采纳 GHC 的建议并启用文件顶部的 MultiParamTypeCLasses
。
{-# LANGUAGE MultiParamTypeClasses #-}
这是一个非常常用的扩展程序,它将解决眼前的问题。
但是似乎存在一些建模问题,如果您继续此设计,您肯定会遇到一些您没有预料到的问题。我可以详细了解您的代码的含义,但我不确定这是否会有帮助。相反,我认为我会为您指明正确的方向,即使用 data
记录而不是类型 类。 Haskell类型类不对应其他OO语言中的类,这让很多初学者感到困惑。但我想你想像这样建模:
data Exchange = Exchange
{ name :: ExchangeName
, base :: Currency
, quote :: Currency
}
data Message = Message
{ time :: Time }
-- etc.
这将为您简化一切,而且它比您的模型更像 OO 类。请记住,记录可以具有函数和其他复杂数据结构作为字段,这就是您获得虚拟方法模拟的方式,例如:
data MessageLogger = MessageLogger
{ log :: String -> IO () }
首先,您可能无法为 ExchangeMessage
编写 class 实例。原因是 exchange
函数必须能够 return any 类型 e
。如果你想保持这种方式,你将需要提供一种构建任意交换的方法!
class Exchange a where
name :: a -> ExchangeName
base :: a -> Currency
quote :: a -> Currency
build :: Time -> a
这是 build
唯一可能的签名,因为你从交易所知道的只是它有一个 Time
你可以查询,它可能没用。
我认为更好的设计是为您定义的所有 classes 提供具体类型。例如:
data Exchange = Exchange { getName :: ExchangeName
, getBase :: Currency
, getQuote :: Currency
} deriving (Show, Eq)
然后,一旦您编写了适用于这些具体类型的函数,您就可以:
- 编写
MyExchange -> Exchange
类型的函数,例如,调整需要 Exchange
的函数
- 使用classy镜头,直接写出会消耗任意类型的函数
总而言之,对于那种应用程序,如果你想对类型感兴趣,我建议你对你的货币使用幻像类型,这样你就可以静态地强制执行,例如你只能计算总和使用相同货币的两笔钱。使用 typeclasses 来模仿 OO 的习惯不会产生很好用的 API 或清晰的代码。
我是 Haskell 的新手,我正在寻找证券交易所库模型。它意味着成为一个图书馆,因此具体细节由用户定义。我打算使用它的方式是让用户定义这样的东西。
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
我尝试了以下方法,但立即 运行 进入了 类 类型的某些限制。下面是代码和错误信息。具体来说,用多种类型参数化类型 类 的替代方法是什么?
这是库的代码
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
错误信息:
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’
稍后我希望能够像这样实现 类 类型:
class Strategy s where
run (Message m, Action a) => s -> m -> a
在 Strategy
实现中,run
函数将采用抽象消息 m,将其与相关 Message
数据构造函数和 return 特定操作进行模式匹配。
我正在移植一些 Scala 代码。在 Scala 中,我使用的是具有具体案例 类 底部的特征层次结构:
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(...)
}
首要任务,采纳 GHC 的建议并启用文件顶部的 MultiParamTypeCLasses
。
{-# LANGUAGE MultiParamTypeClasses #-}
这是一个非常常用的扩展程序,它将解决眼前的问题。
但是似乎存在一些建模问题,如果您继续此设计,您肯定会遇到一些您没有预料到的问题。我可以详细了解您的代码的含义,但我不确定这是否会有帮助。相反,我认为我会为您指明正确的方向,即使用 data
记录而不是类型 类。 Haskell类型类不对应其他OO语言中的类,这让很多初学者感到困惑。但我想你想像这样建模:
data Exchange = Exchange
{ name :: ExchangeName
, base :: Currency
, quote :: Currency
}
data Message = Message
{ time :: Time }
-- etc.
这将为您简化一切,而且它比您的模型更像 OO 类。请记住,记录可以具有函数和其他复杂数据结构作为字段,这就是您获得虚拟方法模拟的方式,例如:
data MessageLogger = MessageLogger
{ log :: String -> IO () }
首先,您可能无法为 ExchangeMessage
编写 class 实例。原因是 exchange
函数必须能够 return any 类型 e
。如果你想保持这种方式,你将需要提供一种构建任意交换的方法!
class Exchange a where
name :: a -> ExchangeName
base :: a -> Currency
quote :: a -> Currency
build :: Time -> a
这是 build
唯一可能的签名,因为你从交易所知道的只是它有一个 Time
你可以查询,它可能没用。
我认为更好的设计是为您定义的所有 classes 提供具体类型。例如:
data Exchange = Exchange { getName :: ExchangeName
, getBase :: Currency
, getQuote :: Currency
} deriving (Show, Eq)
然后,一旦您编写了适用于这些具体类型的函数,您就可以:
- 编写
MyExchange -> Exchange
类型的函数,例如,调整需要Exchange
的函数
- 使用classy镜头,直接写出会消耗任意类型的函数
总而言之,对于那种应用程序,如果你想对类型感兴趣,我建议你对你的货币使用幻像类型,这样你就可以静态地强制执行,例如你只能计算总和使用相同货币的两笔钱。使用 typeclasses 来模仿 OO 的习惯不会产生很好用的 API 或清晰的代码。