riverWM configured with Haskell

I spent the past week or so writing my first actual Haskell program, which is a wrapper over riverctl allowing you to configure riverWM in Haskell! I’d love to see what y’all think about it.

src/ contains the definitions for the functions.

9 Likes

Well, first of all, it’s always great to see someone complete their first Haskell program :smiley: Way to go :tada:

As to what I think, is that looks pretty good. I didn’t see anything that made me think “Oh this is definitely wrong”, so that’s already a win :+1:

A few things that I did notice (and again, read these more as a combination of general best practice, but most are probably also just my personal preference):

  • If you’re using BangPatterns pragma to make the data declarations strict, using StrictData pragma does exactly that :wink:
  • I always prefer less parentheses (e.g. show (MkView a b) = a ++ " " ++ show b)
  • There’s a bunch of argument repetition in definitions like rSnap a = MkPos "snap" a, whereas rSnap = MkPos "snap" means the same thing and (I would argue) is just as readable, if not more.
    I read it as "rSnap is a synonym for MkPos "snap". It’s called “Eta conversion” if you want to look it up. (but you don’t have to)
    Also compare the following:
rSetRepeat = MkTri "set-repeat"
-- which means the same as:
rSetRepeat a b = MkTri "set-repeat" a b
  • In general, Data.Text's Text type is “always” more performant than Strings.
  • The following are identical:
-- if the list only has one element, then
concatMap words [show $ rBackgroundColour a]
-- and
words (show $ rBackgroundColour a)
-- are identical
applyKeybinds a = let x = a in for_ x callRiver
-- and
applyKeybinds a = for_ a callRiver
-- and
applyKeybinds = traverse_ callRiver
map (unwords . words) (join [[show $ function a], [show $ mode a], [show $ modifier a], [key a], z])
-- and
[show $ function a, show $ mode a, show $ modifier a, key a] ++ z
  • riverMapPointer uses error, which is often a sign that the that the type model could be improved. (this is not a strict rule, sometimes it’s just necessary, or way too much of a hassle to change the API)
    In this case, I’d simply return Either String [String], so that Left is the error, and Right is the successful result. It makes it immediately obvious to a person reading the type signature this might fail and that they can handle it, instead of just crashing the program of anyone using it.

Good luck on your Haskell journey!
I hope you’ll have a great time learning more of this wonderful language :grin:

1 Like

It seems to have completely missed my mind to make my code pointfree!
and thanks for telling me about StrictData, it’s very nice.

I did try to use Text but, System.Process wants a String so I’d end up converting back and forth between them (which may or may not be slower).

was actually looking for a nicer way to do this, I love it, thank you! :heart: