我在下面提供了一些代码来演示项目的基本概念。我有模块被设置为接口;我实现了构建模块的接口。在下面的例子中,我构建了一个Alpha
.
type Ticker = String
type Shares = Int
type Price = Float
data Insight = Down | Flat | Up deriving (Show, Eq, Ord)
type Target = Float
data Universe = Universe {generateUniverse :: [(Ticker, Price)] -> [(Ticker, Price)]}
data Alpha = Alpha {generateInsights :: [(Ticker, Price)] -> [(Ticker, Insight)]}
data Portfolio = Portfolio {generateTargets :: [(Ticker, Insight)] -> [(Ticker, Target)]}
data Execution = Execution {generateOrders :: [(Ticker, Price)] -> [(Ticker, Target)] -> [(Ticker, Shares)]}
convert :: (Ticker, Price) -> (Ticker, Insight)
convert (t, p)
| p < 500 = (t, Down)
| p == 500 = (t, Flat)
| p > 500 = (t, Up)
split :: [(Ticker, Price)] -> [(Ticker, Insight)]
split xs = foldr (tp acc -> (convert tp):acc) [] xs
splitAlpha :: Alpha
splitAlpha = Alpha {
generateInsights = split
}
main :: IO ()
main = do
let
alpha = splitAlpha
print (generateInsights alpha [("TSLA", 500.0), ("RKT", 10.0), ("AMC", 750)])
我如何压缩splitAlpha
的定义,使generateInsights
的定义中没有那么多嵌套?我已经尝试了下面的例子…
convert :: (Ticker, Price) -> (Ticker, Insight)
convert (t, p)
| p < 500 = (t, Down)
| p == 500 = (t, Flat)
| p > 500 = (t, Up)
splitAlpha :: Alpha
splitAlpha = Alpha {
generateInsights xs = foldr (tp acc -> (convert tp):acc) [] xs
}
并收到此错误:
ghci> :cmd return $ unlines [":l itk", ":main"]
[1 of 1] Compiling Main ( itk.hs, interpreted )
itk.hs:23:20: error: parse error on input `xs'
|
23 | generateInsights xs = foldr (tp acc -> (convert tp):acc) [] xs
| ^^
Failed, no modules loaded.
<interactive>:60:53: error:
* Variable not in scope: main :: IO a0
* Perhaps you meant `min' (imported from Prelude)
您可以使用lambda表达式,因此:
splitAlpha :: Alpha
splitAlpha = Alpha {
generateInsights =xs ->foldr (tp acc -> (convert tp):acc) [] xs
}
在这个特定的例子中,这只是一个映射函数,所以你可以使用:
splitAlpha :: Alpha
splitAlpha = Alpha {
generateInsights =map convert
}
正如Willem Van Onsem所写,这个例子非常简单,因为整个事情归结为generateInsights = map convert
。但一般来说,这并不容易。Lambda语法只适用于没有保护的单子句函数
splitAlpha = Alpha
{ generateInsights = xs -> ...
}
更一般地说,您总是可以使用let
来拥有一个适当的定义作用域,在这个作用域中,您可以用完整的语法在本地定义任何函数,但避免填充任何其他名称空间:
splitAlpha = Alpha
{ generateInsights
= let gi xs = foldr (tp acc -> (convert tp):acc) [] xs
in gi
}