I have provided some code below that demonstrates the basic concept of a project. I have modules that are set up as interfaces; I implement the interfaces to build modules. In the example below, I built an 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)])
How can I compress my definition of splitAlpha
so that there is not as much nesting in the definition of generateInsights
? I have attempted the example below...
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
}
and recieved this error:
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)
CodePudding user response:
You can work with a lambda expression, so:
splitAlpha :: Alpha
splitAlpha = Alpha {
generateInsights = \xs -> foldr (\tp acc -> (convert tp):acc) [] xs
}
In this specific case however, this is just a mapping function, so you can work with:
splitAlpha :: Alpha
splitAlpha = Alpha {
generateInsights = map convert
}
CodePudding user response:
As Willem Van Onsem wrote, this example is super easy because the whole thing boils down to generateInsights = map convert
. But more generally, it wouldn't be so easy. Lambda syntax only works for single-clause functions with no guards
splitAlpha = Alpha
{ generateInsights = \xs -> ...
}
More generally, you can always use let
to have a proper definition-scope in which you can define any function locally with full syntax available, but avoiding to populate any other namespace:
splitAlpha = Alpha
{ generateInsights
= let gi xs = foldr (\tp acc -> (convert tp):acc) [] xs
in gi
}