"Strategy Template" at Haskell

In the OO world, I have a class (let it "Suggest") to implement something close to the "Strategy Pattern" to provide various implementations of the algorithm at runtime. As an exercise in teaching Haskell, I want to rewrite this.

The actual use case is rather complicated, so I will consider a simpler example.

Let's say I have a class Suggesterthat accepts a list of rules and applies each rule as a filter to the list of database results.

Each rule consists of three steps: Build Query, Post Query Filter, and Scorer. Basically we get an interface corresponding to the following

buildQuery :: Query -> Query
postQueryFilter :: [Record] -> [Record]
scorer :: [Record] -> [(Record, Int)]

The proposal needs to accept a list of rules corresponding to this interface — dynamically at runtime — and then execute them sequentially. buildQuery () must first run according to all the rules, and then postQueryFilter, and then scorer. (i.e. I can't just compose functions for one rule into one function).

in scala I just do

// No state, so a singleton `object` instead of a class is ok
object Rule1 extends Rule {
  def buildQuery ...
  def postQueryFilter ...
  def scorer ...
}

object Rule2 extends Rule { .... }

And then it can initialize the service by passing the appropriate rules through (Defined at runtime based on user input).

val suggester = new Suggester( List(Rule1, Rule2, Rule3) );

If the rules were a single function, it would be simple - just pass the list of functions. However, since each rule is actually three functions, I need to somehow group them, so I have several implementations corresponding to the interface.

, , , - , , .

No parameters for class `Rule`

, haskell, " ", ( , , ).

-,

data Rule = Rule { buildQuery :: Query -> Query, .... etc }

"" . , , , , haskell?

tl; dr - , -, , .

?

+3
2

Rule,

data Rule = Rule
  { buildQuery :: Query -> Query
  , postQueryFilter :: [Record] -> [Record]
  , scorer :: [Record] -> [(Record, Int)]
  }

- , , , Rules SQL

applyRule :: Rule -> Results -> Results

, , , Rule . , , OO.

easyRule :: Rule
easyRule = Rule id id (\recs -> zip recs [1..])

upsideDownRule :: Rule
upsideDownRule = Rule reverse reverse (\recs -> zip recs [-1, -2..])

, Rule,

applyRules :: [Rule] -> Results -> Results
applyRules []     res = res
applyRules (r:rs) res = applyRules rs (applyRule r res)

foldr

applyRules rs res = foldr applyRule res rs

foo :: Results -> Results
foo = applyRules [Some.Module.easyRule, Some.Other.Module.upsideDownRule]
+4

, - "", " " OO: , , Lambdas/Closures/Function Pointers .., "", "" .

"" ( , ). - Haskell, .

+8

All Articles