I want to convert my single file program – which contains the data (alternatives, agents) and functions, into two – one with data (and main program) and another with just the functions.
However, after I split my single file in two – I had to add additional arguments to all the functions, since I no longer had access to global variables alternatives and agents. Is there a way to pass those variables into the second file somehow? Or is there a better alternative that exists in Haskell?
Sorry for the length of the post, but I wanted to illustrate my problem in full.
Initial version, in one file
import Data.List
-----------
-- Setup
-----------
alternatives = [1, 2, 3]
agent_1 x = case x of
1 -> 1
2 -> 0.6
_ -> 0.2
agent_2 x = case x of
1 -> 0.4
2 -> 1
_ -> 0.3
agent_3 x = case x of
1 -> 0.2
2 -> 0.3
_ -> 1
agents = [ agent_1, agent_2, agent_3]
-- collaboration imperative
h x = x^2
-----------
-- Program
-----------
-- Sum of scores by agent
s_i agent = sum [agent(x) | x <- alternatives]
-- Sum of all the scores
s agents = sum [s_i agent | agent <- agents]
-- Importance of an agent
im agent = s_i agent / s agents
-- evaulate agent importances and sort them
agent_ims agents = sort [im agent | agent <- agents]
-- agent scores and importances sorted by scores for a particular alternative 'x'
agent_scores :: Integer -> [(Double, Double)]
agent_scores x = sortBy (\(s1,im1) (s2,im2) -> compare s1 s2)
[(agent x, im agent) | agent <- agents]
num = length(agents)
--U for an alternative 'x' and index 'i'
u x i = sum $ drop (num - i) $ [im | (score, im) <- agent_scores x]
-- 'w' for an agent given a particular collaboration imperative h
-- and alternative 'x'
w i x h = h(u x i) - h(u x (i-1))
-- sort according to which agent's score is the greatest for a given -- alternative
b alt = reverse $ sort [agent alt | agent <- agents]
-- zip 'b' with an index variable, to pass to the w
zipped_alt alt = zip [1..] (b alt)
--group pref function - for an alternative 'x'
g x = sum $ [ w i x h * score | (i, score) <- zipped_alt x]
Version in two files
Test.hs:
import GroupPreference
import Data.List
-----------
-- Setup
-----------
alternatives = [1, 2, 3]
agent_1 x = case x of
1 -> 1
2 -> 0.6
_ -> 0.2
agent_2 x = case x of
1 -> 0.4
2 -> 1
_ -> 0.3
agent_3 x = case x of
1 -> 0.2
2 -> 0.3
_ -> 1
agents = [ agent_1, agent_2, agent_3]
-- collaboration imperative
h x = x^2
main :: IO ()
main = putStrLn $ show $ g 2 h agents alternatives
GroupPreference.hs:
module GroupPreference
where
import Data.List
-----------
-- Program
-----------
-- Sum of scores by agent
s_i agent alternatives = sum [agent(x) | x <- alternatives]
-- Sum of all the scores
s agents alternatives = sum [s_i agent alternatives | agent <- agents]
-- Importance of an agent
im agent agents alternatives = s_i agent alternatives / s agents alternatives
-- agent scores and importances sorted by scores for a particular alternative 'x'
agent_scores x agents alternatives = sortBy (\(s1,im1) (s2,im2) -> compare s1 s2)
[(agent x, im agent agents alternatives) | agent <- agents]
--U for an alternative 'x' and index 'i'
u x i agents alternatives = sum $ drop (length(agents) - i) $ [im | (score, im) <- agent_scores x agents alternatives]
-- 'w' for an agent given a particular collaboration imperative h
-- and alternative 'x'
w i x h agents alternatives = h(u x i agents alternatives) - h(u x (i-1) agents alternatives)
-- sort according to which agent's score is the greatest for a given -- alternative
b alt agents = reverse $ sort [agent alt | agent <- agents]
-- zip 'b' with an index variable, to pass to the w
zipped_alt alt agents = zip [1..] (b alt agents)
--group pref function - for an alternative 'x'
g x h agents alternatives = sum $ [ w i x h agents alternatives * score | (i, score) <- zipped_alt x agents]
I suggest you put the variables in a third module of their own, import it from
GroupPreference, and separate out yourmainfunction into a newMain.hsfile (which is the idiomatic place to putmain; when you leave off the module declaration, it actually defaults toMain, and files should generally be named after the module they define).Another alternative would be to rewrite all your functions to use a
Readermonad, abstracting out the parameter passing — this would force you to restructure your code, and is probably overkill unless you want to vary the parameters at runtime.