-7
$\begingroup$

"As a general principle, make the program read from top to bottom rather than jumping around. Experts agree that top-to-bottom order contributes most to readability."

I think it's difficult to do it in Wolfram Language. It's not a problem in many other languages, however if a function is not defined, I can't use it in Wolfram Language. Is there any way to do it in Wolfram Language?

For instance,

main[x]

main@x_ := h@g@f[x]

h@x_ := x+1
g@x_ := x+2
f@x_ := x+3

Unfortunately it won't work unless you evaluate the code twice.

I guess not everyone knows the advantages of top-to-bottom structure.

Programs/functions are structured in trees , these trees are top-to-bottom. The top of the tree is the highest level, the bottom of the tree is the lowest level.

When you try to understand a function/program, you can start from the highest level at first. If it's necessary, you can study the lower level until you think you have understood the details you need.

enter image description here

Example in Haskell

build :: XcodeScheme -> IO (EBS String)
build xcodeScheme = createBuildOptionSets xcodeScheme >>>= cleanFrameworks >>>= buildFrameworks >>>= combineFrameworks xcodeScheme

createBuildOptionSets :: XcodeScheme -> IO (Either (BuildError String) [XcodebuildOptionSet])
createBuildOptionSets xcodeScheme = getSupportedPlatforms xcodeScheme >>>= createBuildOptionSets' xcodeScheme

cleanFrameworks :: [XcodebuildOptionSet] -> IO (EBS [XcodebuildOptionSet])
cleanFrameworks optionSets = do
    mapM_ cleanFramework optionSets
    return $ Right optionSets

buildFrameworks :: [XcodebuildOptionSet] -> IO (EBS ([XcodebuildOptionSet], [FilePath]))
buildFrameworks optionSets = buildFrameworks' optionSets >>= checkBuildResults optionSets

BTW, the quote is from Wolfram Technology Conference. I can do it in the other languages, I just don't know how to do it in Wolfram Language.

enter image description here

$\endgroup$

closed as primarily opinion-based by Anton Antonov, m_goldberg, MarcoB, happy fish, garej May 31 '17 at 19:37

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 4
    $\begingroup$ I believe such a "general principal" actually goes against philosophy of Wolfram Language $\endgroup$ – QuantumDot May 29 '17 at 14:46
  • 2
    $\begingroup$ So where is the analogous main[x] in your haskell example? $\endgroup$ – Kuba May 29 '17 at 15:39
  • $\begingroup$ That's the entry point. main is defined to be the entry point of a Haskell program (similar to the main function in C) $\endgroup$ – UnchartedWorks May 29 '17 at 15:43
  • $\begingroup$ @Kuba There is another short example in C. repl.it/IWVg $\endgroup$ – UnchartedWorks May 29 '17 at 15:47
  • 2
    $\begingroup$ In interactive Haskell, you cannot invoke main before you have defined it. In compiled Haskell (or C), main is invoked implicitly by the infrastructure after the definitions have been loaded. The top-to-bottom principle as stated is vague, but surely it is violated by evaluating main[x] before defining main. $\endgroup$ – WReach May 29 '17 at 16:11
2
$\begingroup$

Output in a Notebook

From a certain perspective it would seem that you want an output expression to be "aware" of new definitions made that affect it. This is implemented in Dynamic:

main[3] // Dynamic

main@x_ := h@g@f[x]

h@x_ := x + 1
g@x_ := x + 2
f@x_ := x + 3
9

To see this step by step reset the Kernel and evaluate:

main[3] // Dynamic
Pause[1];

main@x_ := h@g@f[x]
Pause[1];

h@x_ := x + 1
Pause[1];

g@x_ := x + 2
Pause[1];

f@x_ := x + 3

(* main[3] -> h[g[f[3]]] -> 1 + g[f[3]] -> 3 + f[3] -> 9 *)

Programmatic usage

From another more programmatic perspective your code already works. Again in a fresh kernel:

result = main[3];

main@x_ := h@g@f[x]

h@x_ := x + 1
g@x_ := x + 2
f@x_ := x + 3

When result is used it behaves as desired, e.g.:

IntegerQ[result]
Print[result]
True

9
$\endgroup$
8
$\begingroup$

The quote comes from a presentation which advocates using postfix notation more widely. It asserts that writing

x //
f //
g //
h

is superior to

h @
g @
f @
x

or

h[
  g[
    f[
      x
     ]
   ]
 ]

As one argument it invokes the so-called "top-to-bottom principle" which asserts that it is easier to read code if the top-to-bottom textual order matches the execution order.

If we accept this principle, then the example given is in violation since main[x] must be executed after the following definitions have been established. To conform to the principle, main[x] should be last.

In the comments to the question there is discussion concerning the use of main in Haskell and C. Like Mathematica, interactive Haskell demands that main be defined before it is executed. In compiled Haskell and C, the invocation of main is implicit -- but occurs after the source code has been compiled, linked and loaded. Mathematica has no notion of an implicit main program.

The top-to-bottom principle can never be considered absolute. Code execution is resolved to a well-ordered set of instructions (to a good approximation, on conventional architectures). By contrast, code definitions form a general network that cannot always be linearized.

But definitions must always be established chronologically before they are executed. So, to conform to the principle, definitions must also precede executions textually. In this regard, the ability to conform would seem to be no worse in Mathematica than other languages (including Haskell and C).

$\endgroup$
5
$\begingroup$

It seems that OP is thinking too much in terms of Haskell. I would suggest to get more experienced with WL / Mathematica -- it belongs to a different functional programming paradigm with a (much) older pedigree than the one of Haskell.

So, one of the possible answers for OP question is to read / study the following references.

  1. The Paul Graham's book "On Lisp", Prentice Hall, 1993, 432 pages, paperback. ISBN 0130305529. (Or at least its preface.)

  2. Answers of "General strategies to write big code in Mathematica?".

  3. Answers of "Where can I find examples of good Mathematica programming practice?".

  4. And for a serious case study, answers of "Can one identify the design patterns of Mathematica?".

Something to keep in mind:

  • Mathematica / WL programmers often think in terms of the corresponding Abstract Syntax Tree (AST);
  • Haskell programmers are too much into the declarative thinking that comes with Haskell's type system.

(Of course, Haskell programs ultimately get transformed to AST.)

$\endgroup$
0
$\begingroup$

I think it's achievable. Actually it doesn't have to be against the philosophy of Wolfram Language. I suppose that "Everything is an expression" is part of the philosophy.

I made a mistake in my first example in Wolfram Language.

In:

main[x]

main@x_ := h@g@f[x]

h@x_ := x+1
g@x_ := x+2
f@x_ := x+3

Out:

main[x]

The "mistake" is subtle. If we follow the spirit of Wolfram Language, we could rewrite the code as an expression.

In:

(*Function *)
main[h_, g_, f_, x_] := h@g@f[x]

h@x_ := x + 1
g@x_ := x + 2
f@x_ := x + 3

(*Evaluating Functions*)
main[h, g, f, 3]

Out:

9

How it works

To explain how it works, we can transform the expression to a tree.

TreeForm@Defer@main[h, g, f, 3]

Mathematica graphics

Before I rewrote the code, I used 3 free variables in main. That's why the output of the old code is main[x]. In the new code, I used bounded variables, so it doesn't matter that I define main before f, g and h.

Free variable & Bounded variable

A free variable is a notation that specifies places in an expression where substitution may take place.

A bound variable is a variable that was previously free, but has been bound to a specific value or set of values.

$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.