Encapsulating a list of functions in haskell in a single one
Someone said that I might not be "getting" how to proper code in Haskell. That someone must be totally right, as I feel all my haskell code but the simpler functions is really ugly (at least compared to my OOP code in a "standard" language such as Java or C++):
mev = matrixExpValues开发者_StackOverflow中文版 5 4 3
cs = canonicalSt 4 3
cs_t1 = map (foldl (++) "") (map (map show) cs)
cs_t2 = map (++ ":") cs_t1
mev_t1 = intXxsToStringXxs mev
mev_t2 = map (map (++ "\t")) mev_t1
mev_t3 = map (foldl (++) "") mev_t2
res1 = zipWith (++) (map (++ "\t") cs_t2) mev_t3
res2 = map (++ "\n") res1
final_result = foldl (++) "" res2
with mev
and cs
of:
*Main> mev
[[2,-2,-2,-6],[4,2,0,-2],[2,2,4,4],[6,4,2,2],[6,4,2,6]]
*Main> cs
[[0,0,4],[0,1,3],[0,2,2],[1,1,2]]
(those values were hand typed, I will need this to work for arbitrary mev
and cs
!)
I initially have a 2D matrix to which I applied a sequence of operations until I got the desired result.
This works, but now I'd like to encapsulate all this logic in a single function (let's call it matrix_transf
). The current code is tied to what matrixExpValues
and canonicalSt
return, and I'd like to have something like
matrix_transf mev cs =
...all those transformations
...until I get to final_result
All kind of criticism is welcome (I need it so I can improve!) I believe good Haskell coders will probably approach this in a total different way and that is what I am looking for to know!
Know the library. For example,
foldl (++) "" x
can be replaced byconcat
, the++ "\t"
stuff etc. can be done byData.List.intercalate
, etc.You could use
where
andlet
to define local 'variables'.
Assume you want to convert the 2 lists into the form
004: 2 -2 -2 -6
013: 4 2 0 -2
...
then I would write
import Data.List
matrix_transf mev cs =
unlines $ zipWith processEntry mev cs
where processEntry mev_entry cs_entry =
concatMap show cs_entry ++ ":\t" ++
intercalate "\t" (map show mev_entry)
*Main> putStrLn $ matrix_transf [[2,-2,-2,-6],[4,2,0,-2],[2,2,4,4],[6,4,2,2],[6,4,2,6]] [[0,0,4],[0,1,3],[0,2,2],[1,1,2]]
004: 2 -2 -2 -6
013: 4 2 0 -2
022: 2 2 4 4
112: 6 4 2 2
(Note that this is different from your function where the trailing tabs do not exist.)
First I would like to say that what I am going to show you isn't optimal (for instance KennyTM's code looks a whole lot better.) But I would like to show you how your code would look if you change intXxsToStringXxs
to map (map show)
and continuously apply the rule :
map f (map g xs)
==>map (f.g) xs
while inlining definitions when possible. Also, to make it look better, I have applied these rules:
foldl (++) ""
==>concat
concat (map f xs)
==>concatMap f xs
concatMap (++ "\n")
==>unlines
Afer quite a lof of rewriting, it will give you this:
cs_t3 = map ((++ ":\t") . concatMap show) cs
mev_t3 = map (concatMap ((++"\t") . show)) mev
final_result = unlines (zipWith (++) cs_t3 mev_t3)
I know it doesn't look much better, but it shouldn't take you too long now to figure out that you can write matrix_transf
like this:
matrix_transf mev cs = unlines (zipWith (++) (starts cs) (endings mev))
starts = map ((++ ":\t") . (concatMap show))
endings = map (concatMap ((++"\t") . show))
or even like this:
matrix_transf mev cs = unlines . zipWith (++) starts $ endings
where starts = map ((++ ":\t") . (concatMap show)) cs
endings = map (concatMap ((++"\t") . show)) mev
Funny how the previous solutions still treat the tab after the colon differently from the tab after each field. When I dump a table, I usually treat each field as starting with a tab instead of ending with a tab. I also think the version from @KennyTM is more readable:
matrix_transf mev cs =
unlines $ zipWith processEntry mev cs
where processEntry mev_entry cs_entry =
concatMap show cs_entry ++ ":" ++
concapMap (("\t" ++) . show) mev_entry
精彩评论