How Do Convert This Code And My Thinking To A Functional Mindset (clojure)?
Solution 1:
How to start thinking in a functional way? There is no short cuts and quick answers. You have to invest a good amount of time trying to code in functional way.
You can start by morphing simple algorithms. But it is important to keep in mind that in functional programming you care about data flow, not how to instruct the CPU to do this and that.
It is important to know the core functions in your language. From those core functions, you can start transform you data. Kind of Lego or DNA stripes if you want.
If you are interested in Clojure particularly, then I recommend to spend good time on 4Clojure and Land of Lisp.
And Clojure IRC is a wonderful place to learn from Rockstars Clojure developers. Friendly community and helpful for sure.
Always remember: "OOP isn't easy by default and FP isn't hard by default".
Solution 2:
Well the data will look more or less identical:
(def world [[{:x1, :y2, :fill0}, {:x2, :y2, :fill0}]
[{:x1, :y1, :fill0}, {:x2, :y2, :fill1}]])
but for the print function you can use doseq
(defn print-world [world]
(doseq [row world]
(doseq [cell row]
(print (str "[" (:fill cell) "]")))
(println)))
(print-world world)
;; outputs
;; [0][0]
;; [0][1]
and to change elements, assoc-in
or update-in
; move the filled cell 'up'
(print-world
(-> world
(assoc-in [11 :fill] 0) ; set bottom-right fill to0
(assoc-in [01 :fill] 1))) ; set top-right fill to1
;; outputs
;; [0][1]
;; [0][0]
Clojure isn't the best fit for this kind of programming, but it is useful stuff to know.
Edit: as for thinking in a functional way, that's not the kind of skill that can be easily conveyed through a stackoverflow answer. It takes a good deal of writing code and reading other people's code. A great place to start online would be Clojure for the Brave and True. The thing that got me thinking functionally was the wonderful Learn you a Haskell for Great Good!.
Solution 3:
When trying to get into "the functional way of thinking" it sometimes helps to look at code and think of ways to separate the separable parts. In this example there are three logical phases:
- change the data to contain only the filter field
- put it in vector form (with the
[]
s) - print it nicely
If we seperate these into their own Clojure expressions then perhaps you will be able to reuse one of them elsewhere, or write better tests etc. as opposed to doing both actions in the same pass through the matrix (which is admittedly, slightly more efficient)
user> (def world [[{:x1, :y4, :fill0 }, {:x2, :y4, :fill0 }, {:x3, :y4, :fill0 }, {:x4, :y4, :fill0 }],
[{:x1, :y3, :fill0 }, {:x2, :y3, :fill0 }, {:x3, :y3, :fill0 }, {:x4, :y3, :fill0 }],
[{:x1, :y2, :fill0 }, {:x2, :y2, :fill0 }, {:x3, :y2, :fill0 }, {:x4, :y2, :fill0 }],
[{:x1, :y1, :fill0 }, {:x2, :y1, :fill0 }, {:x3, :y1, :fill1 }, {:x4, :y1, :fill0 }]])
#'user/world
user> (defn filter-fill [world] (map #(map :fill %) world))#'user/filter-fill
user> (filter-fill world)
((0000) (0000) (0000) (0010))
user> (defn vector-world [world] (mapv #(mapv vector %) world))#'user/vector-world
user> (clojure.pprint/pprint (vector-world (filter-fill world)))
[[[0] [0] [0] [0]]
[[0] [0] [0] [0]]
[[0] [0] [0] [0]]
[[0] [0] [1] [0]]]
nil
Solution 4:
This sketch generates the states of the world rather than mutating a structure in memory. In Rich Hickey speak, it generates the next value instead of storing something different at the same old place.
// world is an object with the world's statevar world = function(tl, tr, bl, br){
this.state = {topLeft: tl, topRight: tr, bottomLeft: bl, bottomRight: br};
};
// screen is an object with internal state that represents// the state of the of the worldvar screen = function(aWorld){
this.state = [[{fill: aWorld.state.topLeft},
{fill: aWorld.state.topRight}],
[{fill: aWorld.state.bottomLeft},
{fill: aWorld.state.bottomRight}]];
};
// showScreen is a function in which all side// effects occur.functionshowScreen(aScreen){
var out = "";
for (var line = 0; line < aScreen.state.length; line++){
for (var pix = 0; pix < aScreen.state[line].length; pix++){
out += "[" + aScreen.state[line][pix].fill + "]";
}
out += "\n"
}
console.log(out);
}
// here is the heart of functional style programming:// generating the next value instead of changing// some existing statefunctionnextWorld(tr,tl,br,bl){
showScreen(newscreen(newworld(tr,tl,br,bl)))
}
// turn off screenfunctionscreenOff(){
nextWorld(0,0,0,0)
}
// make a forward slashfunctionforwardSlash(){
nextWorld(1,0,0,1)
}
Post a Comment for "How Do Convert This Code And My Thinking To A Functional Mindset (clojure)?"