-1

Let us consider the following haskell program :

g::Int
g = 300

func::Int->Int
func arg = arg + g

main = do
  print (func 4)

I don't particularly like this program because "func" is using the global variable g in its computation, and I would like to aim that all functions written in my program specify as arguments all the elements needed to perform the necessary computations (i.e. nothing outside the function is used).

My question is this : is there any way to get ghc to reject functions which use variables not defined in the argument list? (rather than having to rely on pure discipline)...

[EDIT] : Also consider the following :

main.hs :

import MyMod

func::Int->Int
func arg = arg + g

main = do
  print (func 4)

MyMod.hs

module MyMod where

g::Int
g = 300

[EDIT2] : I guess that if functions could only use variables defined in the argument list then one would have to make exceptions (?) for things like :

g::Int
g = 300

h::Int
h = 400

i::Int
i = g + h

[EDIT3] : For n.m. in response to "Try writing a complete program with these restrictions that has more than one function" (the restriction being that functions can only use variables declared in their argument list). Ofcourse there has to be exceptions and in this case the main is the exception. This example was adapted from Comparing speed of Haskell and C for the computation of primes

divisibleRec :: Int -> Int -> Bool
divisibleRec i j 
  | j == 1         = False 
  | i `rem` j == 0 = True 
  | otherwise      = divisibleRec i (j-1)

divisible::Int->(Int -> Int -> Bool)-> Bool
divisible i fn= (fn i (i-1))

main :: IO()
main = print(length([ x | x <- [2..1000], (divisible x divisibleRec) == False]))

[EDIT 4] : In regards to the program in EDIT3, recursive usage as in divisibleRec would also have to be an exception, since the inside "divisibleRec" is not fed as an argument to the function.

Also this rule becomes unmaintainable when we chain many functions together. In the program above it was not too bad, we just had "divisible x divisibleRec", but as we have bigger programs the scheme above become unmaintainable since we effectively have to chain all the functions in one place....

[EDIT 5] : When I originally posted this question, I was viewing functions and variables on a different level. However when you treat functions on the same level as variables, so that the restriction "all functions written in my program specify as arguments all the elements needed to perform the necessary computations (i.e. nothing outside the function is used)" means that functions which use other functions must be passed these other functions as arguments, then the whole approach becomes unmaintainable for the reasons mentioned in Edit4.

Community
  • 1
  • 1
artella
  • 5,068
  • 4
  • 27
  • 35
  • 11
    `func` is also a global variable. So is `main`. – n. m. could be an AI Oct 29 '12 at 20:55
  • @n.m. func is a global function, as opposed to global variable, no? – artella Oct 29 '12 at 20:59
  • Why are you concerned about this? There's nothing wrong with global variables as long as they're immutable, which everything is by default in Haskell. – hammar Oct 29 '12 at 20:59
  • @hammer I'm not particularly worried about it, but I dont think that it is good style, and just wanted to know if there are mechanisms for ghc to warn/reject such functions. – artella Oct 29 '12 at 21:02
  • 6
    `foo` is a variable that happens to have a functional type. `main` does not even have a functional type. It's of type `IO ()`. See, no arrow there. It's just a variable, not different from `g` in any way. How do you propose to distinguish between them? – n. m. could be an AI Oct 29 '12 at 21:04
  • @n.m. Hmm that is interesting. I hadn't thought of functions (like foo) as "generalised" variables.... – artella Oct 29 '12 at 21:08
  • 7
    @artella And any sense you have that globals are bad style almost certainly comes from languages with global *mutable* values. With immutable values, it really doesn't matter. – Carl Oct 29 '12 at 21:09
  • 2
    Functions are first-class values. This is **the** thing of functional programming. – n. m. could be an AI Oct 29 '12 at 21:10
  • @Carl whilst writing this post the mutability versus immutability did cross my mind, but I still felt that using global variables was a bit dirty. However in light of n.m.'s comments I am beginning to doubt whether having such a warning is a sensible thing at all... – artella Oct 29 '12 at 21:34
  • 3
    Note that `+` is a global variable too! So to avoid use of globals, `func` would have to be defined as `func op g arg = op arg g`. But then whatever calls it would be calling `func (+) 300 4`, so *that* function would have to be modified to take `op` as an argument so it can do `func op arg g`. It *is* technically possible to program completely without any global variables in the lambda calculus, by writing your entire function as a nested-lambda applied to all the values you need "global" access to, but given that you can't define many built-ins within Haskell itself, you can't use them. – Ben Oct 29 '12 at 23:24
  • 4
    Ignoring the point about functions being variables (and often global in scope), I think we could all help you better if you gave some motivation for your question. From an engineering perspective there doesn't seem to be any benefit to not using globals with low arity. – Thomas M. DuBuisson Oct 30 '12 at 02:58
  • 1
    A comment on terminology: Calling your functions (global) _variables_ is a [misnomer](https://en.wikipedia.org/wiki/Misnomer) - it leads to the conclusion that they can _vary_, they can change. In pure functional programming we have no variables, we only [bind](https://en.wikipedia.org/wiki/Name_binding) names to functions and these bindings can never change then. So a more appropriate terminology would be to call them _bindings_ or _(named) functions_. – Petr Oct 30 '12 at 07:08
  • @Thomas M. DuBuisson : In regards to some motivation : I know this is quite different from Haskell, but as an example I have worked with VBA in excel sheets where I have come across functions which suddenly call data from worksheets as opposed to specifying the data as function arguments. I dislike this approach and much prefer all the data to be extracted from the worksheets in one place, and from thereon use functions which operate on only data specified in arguments -> see next comment for continuation.... – artella Oct 30 '12 at 07:47
  • @Thomas M. DuBuisson : ...[continued] That way I can isolate data extraction in one place. Also if I make changes to the excel sheet, then the changes I have to make to the vba code are localized to the data extraction area, rather than having to find every place where a function makes a direct extraction from this specific worksheet. If named ranges had been used (by this function) then I guess this would not have been as much of an issue..... – artella Oct 30 '12 at 07:52
  • @Thomas M. DuBuisson : I guess this is more about functions accessing data defined outside the function (which were not specified as arguments), as opposed to global variables.. – artella Oct 30 '12 at 08:03
  • @n.m. even if foo is a variable, would it not make sense (from a language design perspective, with respect to tidyness) to constrain (even though we know about immutability) the function to only be able to use data as specified by the arguments? Forgetting about main, one could make the distinction by saying that any thing that has an arrow (->) in the type declaration can only use things specified in the argument list...But maybe such a thing would cause problems for code like in Edit 2. I need to think about it a bit more. – artella Oct 30 '12 at 09:02
  • 1
    @artella When thinking about it a bit more, consider how `g = 300` is actually a *function* taking no parameters and returning `300`. – Deestan Oct 30 '12 at 09:13
  • If all you can use is the list of arguments, how do you access **anything**? Try writing a complete program with these restrictions that has more than one function. – n. m. could be an AI Oct 30 '12 at 10:21
  • (@Deestan, pedantically, [that's not actually true](http://conal.net/blog/posts/everything-is-a-function-in-haskell).) – huon Oct 30 '12 at 13:06
  • @n.m. Regarding an example, how about the program in Edit4? There have to be exceptions to this rule e.g. the main in the program above, but if there are exceptions (which are easy to keep track of via their declarations) then surely this rule is possible? Thanks – artella Oct 30 '12 at 15:29
  • @n.m. Actually thinking about it as more functions are chained in the manner above (in main), then the restriction I mentioned above becomes unworkable..... – artella Oct 30 '12 at 15:32
  • @n.m. And also recursive usage as in divisibleRec would have to be another exception since technically I havent passed the inside divisibleRec as an argument... – artella Oct 30 '12 at 15:36
  • @n.m. My mistake was again thinking of functions and variables on a "different level" (see edit 5)...I only realised the unfeasibility of my rule when I followed your suggestion and wrote a program, this time treating functions and variables in the same manner. Thanks – artella Oct 30 '12 at 16:04
  • Ok so `main` is the exception and all the globals are concentrated there and passed to every other function. I think after your program passes 10000 functions in size you will start looking for better ways to kill your weekend. – n. m. could be an AI Oct 30 '12 at 16:06
  • @n.m. yes I only realised how ridiculous it becomes when I treated "Functions are first-class values" (edit 5). – artella Oct 30 '12 at 16:31
  • 1
    @n.m. "I think after your program passes 10000 functions in size you will start looking for better ways to kill your weekend" - no two functions is quite enough!:) – artella Oct 30 '12 at 16:33

1 Answers1

1

Theoretically, you could use combinatory logic without free variables (lambda-terms captured from the outside of function) whatsoever (that's how your request is expressed in terms of lambda calculus), but it must be very unpractical and cumbersome, like an esoteric programming language.

As pointed out in the comments, any "value" is a function (even without arguments). The main obstacle I see in no using free variables is that any input/output functions are external to your functions, so the pure combinatory program can't do any IO and is even more useless than Haskell itself (according to SPJ saying that Haskell is useless:) ). Moreover, you are left without any library functions, which only may be useful for some mathematical exercises, not for programming.

Another question is whether it is possible locally, in some subset of functions, but I doubt GHC or any other Haskell implementation allows this.

There are some implementations of combinatory logic interpreters, but I see no efforts to make Haskell pure combinatory.

Conclusion: this question rather belongs to area of language design and choice of underlying mathematical formalism. Haskell (based on lambda calculus with free variables) is definitely distinct from what you want. Introducing such constraints to Haskell would make it another language, though you can observe discipline in code to make it partly combinatory. Introducing restriction on free "values" (no-argument functions) is mathematically meaningless, so it's very unlikely that there are built-in Haskell mechanisms for doing this.

Dmytro Sirenko
  • 5,003
  • 21
  • 26
  • when I originally posted the question I was making the distinction between values and functions. However as n.m. pointed out "Functions are first-class values". Following his suggestion I rewrote a program, this time implementing the rule "all functions specify as arguments all the elements needed to perform the necessary computations" (see Edit 3). However the problem (see Edit 5) is that all the functions have to be declared in main and this becomes unmanageable. – artella Oct 30 '12 at 16:40
  • @artella Yes, that's just the first limitation of pure combinatory style, and there is a lot of others. The only useful application of CL I've encountered is writing libraries in combinatory style at large scale. – Dmytro Sirenko Oct 30 '12 at 16:44
  • sorry what do you mean by "is writing libraries in combinatory style at large scale"? Can you give an example? Thanks – artella Oct 30 '12 at 22:00