Heckel ternary operator

I often use list comprehension for optional values:

[Parent parent, Destination [DestPage currPage]] ++ [OpenChildren | parent == Bookmark 0] 

But I do not know how to make a choice instead of an optional value.

A lot of my code looks like this:

 let lblTabX = if isAtBottom then 5 else 3 lblTabY = if isAtBottom then 3 else 60 lblTabPosition = Position left (if isAtBottom then bottom else top) lblTabWidth = if isAtBottom then lblPageX - 60 else 20 lblTabHeight = if isAtBottom then 20 else pageHeight - 80 lblTabMargin = if isAtBottom then Margin 0 3 else Margin 3 0 

As you see a lot of ifs :)

So, I played with some operators and came up with this syntax:

 iif clr = if c then l else r infixl 8 <-/ (<-/) lc = iif cl infixl 8 /-> (/->) = ($) 

And I like what the previous example looks like:

 let lblTabX = 5 <-/ isAtBottom /-> 3 lblTabY = 3 <-/ isAtBottom /-> 60 lblTabPosition = Position left (bottom <-/ isAtBottom /-> top) lblTabWidth = (lblPageX - 60) <-/ isAtBottom /-> 20 lblTabHeight = 20 <-/ isAtBottom /-> (pageHeight - 80) lblTabMargin = Margin 0 3 <-/ isAtBottom /-> Margin 3 0 

This, of course, is a toy example. I am not going to use it. But I was just curious if there is syntax for the expression of choice other than the if statement? Maybe with a list?

+6
source share
4 answers

if at Haskell are not very pretty, but that’s not the reason they are so rarely used. This is more because there is usually a more elegant syntax alternative! In your example, I would consider

 let ( lblTabX, lblTabY, lblTabPosition, lblTabWidth, lblTabHeight, lblTabMargin ) | isAtBottom =( 5, 3, bottom, lblPageX-60, 20, Margin 0 3 ) | otherwise =( 3, 60, top, 20, pageHeight - 80, Margin 3 0 ) 

Alternatively, you can define a locally processed statement locally:

 let bottomCase/|/topCase | isAtBottom = bottomCase | otherwise = topCase lblTabY = 3 /|/ 60 lblTabPosition = Position left $ bottom /|/ top lblTabWidth = (lblPageX - 60) /|/ 20 lblTabHeight = 20 /|/ (pageHeight - 80) lblTabMargin = Margin 0 3 /|/ Margin 3 0 

You definitely don't want to check for isAtBottom several times, redundant code is always bad, no matter what syntax you use. But when you just need one solution based on a simple boolean, I would stick with the standard if , rather than defining user-defined operators.

+9
source

Oh, get rid of all these conventions. You have many related settings that in one context will have one set of values, in another context a different set.

 data TabConfig = TabConfig { tabX, tabY, tabWidth, tabHeight :: Int, tabPosition :: Position, tabMargin :: Margin } 

(You do not need to use the syntax of the entry, I do this for clarity)

Now you just need to provide your functions with the appropriate TabConfig , from which they can extract values. You can provide the defaultConfig function ...

 defaultConfig :: Context -> TabConfig defaultConfig c = TabConfig { 5, 3, 20, (pageHeight c) - 80, Position left bottom, Margin 3 0 } 

You can also have

 bottomConfig :: Context -> TabConfig bottomConfig c = TabConfig { 3, 60, (pageX c) - 60, 20, Position left top, Margin 0 3 } 

Then you simply specify the appropriate TabConfig in the appropriate context. (I hope you found out that Context is a different type of recording style, and of course you can play with the same tricks).

If more parameters are added to TabConfig, and only a few are at the bottom, you can do

 bottomConfig c = let def = defaultConfig c in def { tabX = 3, tabY = 60, ... 

Just create the correct configuration for the current context and make it available to your functions. Why should your table-drawing functions need to know about the logic you use to determine how their position on a page limits their size? What happens when new conditions impose additional restrictions? Mixing them up is terrible. Separation of problems is at least as important for functional programming as it is in OO. TO

Of course, I'm trying to hint that you need a Reader monad. But the reader monad is so simple that you don't need to know that you use it if the monads are still discouraged.

+4
source

in the following (?) GHC in Data.Bool we will have a bool function:

 bool :: a -> a -> Bool -> a bool f _ False = f bool _ t True = t 

And we could rewrite your example:

 lblTabX = bool 3 5 isAtBottom 
+3
source

Matching the pattern is the basic syntax of choice, most of the rest is expressed in terms of this. ( if defined in terms of an equivalent case expression, for example).

0
source

Source: https://habr.com/ru/post/956920/


All Articles