https://github.com/kachayev/fn.py/blob/master/README.rst#scala-style-lambdas-definition



On Monday, August 21, 2017, Chris Barker <[email protected]> wrote:

>
>
> On Sat, Aug 19, 2017 at 3:34 AM, ?? ? <[email protected]
> <javascript:_e(%7B%7D,'cvml','[email protected]');>> wrote:
>
>> Could you please think this way to define a variable:
>>
>> >> var = expr() -> g1(_) if f(_) else g2(_)
>>
>> which equals
>>
>> >> test = f(expr())
>> >> var  = g1(test) if f(test) else g2(test)
>>
>
> OK, I do see this as a nice way to avoid as many "temp" variables, though
> in this example, I am confused:
>
> in the above version, It seems to me that the equivelent wordy version is:
>
> temp = expr()
> var = g1(temp) if f(temp) else g(temp)
>
> rather than the f(expr()) -- i.e. you seem to have called f() on expr and
> extra time? Maybe just a typo.
>
> or, of course:
>
> var = g1(expr()) if f(expr()) else g(expr())
>
> which I can see would be bad if expr() is expensive (or even worse, has
> side effects)
>
> so I'm coming around this this, though you could currently write that as:
>
> _ = expr(); g1(_) if f(_) else g(_)
>
> not that different!
>
> Also, there is something to be said for giving a name to expr() -- it may
> make the code more readable.
>
>
> In another words,I can clearly state what I mean to say in order of my
>> thinking.
>>
>
> well, in the above case, particularly if you use a meaningful name, rather
> than "temp" or "test", then you are still writing in in the order of
> meaning.
>
> (though elsewhere in this thread there are better examples of how the
> current nested function call syntax does reverse the logical order of
> operations)
>
>
>> For example,
>>
>> >> lambda x: f(g(x)) -> map(_, range(100))
>>
>> The codes above means that I'm stressing on what(an action) I'm going to
>> do on an object "range(100)".
>>
>
> This is still putting the range(100) at the end of the expression, rather
> than making it clear that you are starting with it.
>
> and putting that much logic in a lambda can be confusing -- in fact, I'm
> still not sure what that does! (I guess I am still not sure of the order of
> operations is the lambda expression (f(g(x))) or the whole thing? if not
> the whole thing, then:
>
> is it the same as ?:
>
> (f(g(x)) for x in range(100))
>
> I'm also seeing a nested function there -- f(g(x)) which is what I
> thought you were trying to avoid -- maybe:
>
> lambda x: (g(x) -> f(_)) -> map(_, range(100))
>
> ???
>
> In general, much of this seems to be trying to make map cleaner or more
> clear -- but python has comprehensions, which so far work better, and are
> more compact and clear for the examples you have provided.
>
> granted, deeply nested comprehensions can be pretty ugly -- maybe this
> will be clearer for those??
>
>
> However, sometimes the actions are not important, so if we want to stress
>> on what we're going to do something on, we write this codes:
>>
>> >> range(100) -> map( lambda x:f(g(x)), _ )
>>
>
> OK, so THAT makes more sense to me  -- start with the "source data", then
> go to the action on it.
>
> but again, is that really clearer than the comprehension (generator
> expression - why don't we call that a generator comprehension?):
>
> (f(g(x)) for x in range(100))
>
>  maybe this would be better:
>
> range(100) -> (f(g(x)) for x in _)
>
> it does put the source data up front -- and could be nicer for nested
> comprehensions.
>
> Hmm, maybe this is an example of the kind of thing I've needed to do is
> illustrative:
>
>
> [s.upper() for s in
>         (s.replace('"','') for s in
>         (s.strip() for s in
>         line.split()))]
>
> would be better as:
>
> line.split() -> (s.strip() for s in _) -> (s.replace('"','') for s in _)
> ->  [s.upper() for s in _]
>
> though, actually, really best as:
>
> [s.strip().replace('"','').upper() for s in line.split()]
>
> (which only works for methods, not general functions)
>
> but for functions:
>
> [fun3(fun2(fun1(x))) for x in an_iterable]
>
>
> so, backwards logic, but that's it for the benefit.
>
> So still having a hard time comeing up with an example that's notable
> better...
>
> >> someone -> dosomething( _, options=options) \
>>            -> is_meeting_some_conditions( _ )  \
>>            -> result1() if _ else result2()    where:
>> options = ...
>> result1 = lambda: ...
>> result2 = lambda: ...
>> def dosomething(obj, options) -> Any:
>> ...
>>
>> def is_meeting_some_conditions( event : Any ) -> bool :
>> ...
>>
>
> again with the lambdas -- this is all making me think that this is about
> making Python a better functional language, which I'm not sure is a goal of
> Python...
>
> but anyway, the real extra there is the where: clause
>
> But that seems to be doing the opposite -- putting the definitions of what
> you are actually doing AFTER the logic>
>
> I'm going to chain all this logic together
> and by the way, this is what that logic is...
>
> If we really  wanted to have a kind of context like that, maybe something
> more like a context manager on the fly:
>
> with:
>     options = ...
>     result1 = lambda: ...
>     result2 = lambda: ...
>     def dosomething(obj, options) -> Any:
>         ...
>
>     def is_meeting_some_conditions( event : Any ) -> bool :
>         ...
> do:
>     (result1() if is_meeting_some_conditions(
>                  dosomething( someone, options=options))
>          else result2()
>
> > Also,  we need to remember that functions can take *args, **kwargs, etc,
>> > and can return a tuple of just about anything -- not sure how well that
>> > maps to the "pipe" model.
>>
>> I think that using "pipe" model cannot be the right choice.
>>
>> We don't need to worry about this problem if we use the grammar I've
>> implemented yet :)
>>
>>   >> (lambda x: (x%5, x) ) ->  max( range(99), key = _)
>>   >> 94
>>
>>   >> def max_from_seq(*args): return max(args)
>>   >> [1,2,3] -> max_from_seq(*_)
>>   >> 3
>>
>
> this gets uglier if we have both *args and **kwargs.....
>
> Which maybe is OK -- don't use it with complex structures like that.
>
>  For example, sometimes we just need to know that surface area of a
>> cylinder is
>>
>>    2*S_top + S_side
>>
>>  If someone see the codes, he may not need to know how S_top and S_side
>> are evaluated,getting
>>  a knowledge of what it means to is enough.
>>  And if you want to get more about how to evaluate S_side and S_top, just
>> see
>>  the next "where syntax" and find the answers.
>>
>
> how is that clearer than:
>
> S_topo = something
> S_side = something else
> surface_area = 2*S_top + S_side
>
> ???
> (Or, of course, defining a function)
>
> Sure, we see the: some expression..."where" some definitions structure a
> lot in technical papers, but frankly:
>
> I'd probably rather see the definitions first
>
> and/or
>
> the definitions are often only there to support you if you don't already
> know the nomenclature -- when you go back to read the paper again, you may
> not need the where. Coding is different, I'd rather see stuff defined
> BEFORE it is used.
>
>
> >> Here is an example to use flowpython, which gives the permutations of a
>> sequence.
>> >>
>> >>     from copy import deepcopy
>> >>     permutations = .seq -> seq_seq where:
>> >>         condic+[] seq:
>> >>             case (a,  ) => seq_seq = [a,]
>> >>             case (a, b) => seq_seq = [[a,b],[b,a]]
>> >>             case (a,*b) =>
>> >>                 seq_seq = permutations(b) -> map(.x -> insertAll(x,
>> a),  _) -> sum(_, []) where:
>> >>                      insertAll = . x, a -> ret where:
>> >>                          ret = [ deepcopy(x) -> _.insert(i, a) or _
>> for i in  (len(x) -> range(_+1))  ]
>>
>> > I find that almost unreadable.
>>
>
> me too.
>
>
>> Too many new features all at once, it's
>> > like trying to read a completely unfamiliar language.
>>
>
> exactly -- this seems to be an effort to make Python a different language!
>
> This algorithm can be fixed a little because the second case is redundant.
>> And here is the regular Python codes transformed
>> from the codes above.
>>
>
> looks like we lost indenting, so I'm going to try to fix that:
>
> from copy import deepcopy
>
> def permutations(seq):
>     try:
>         # the first case
>         (a, ) = seq
>         return [a ,]
>     except:
>         try:
>             # the third case (the second case is redundant)
>             def insertAll(x, a):
>                 # insertAll([1,2,3], 0) -> [[0, 1, 2, 3], [1, 0, 2, 3],
> [1, 2, 0, 3], [1, 2, 3, 0]]
>                 ret = []
>                 for i in range( len(x) + 1 ):
>                     tmp = deepcopy(x)
>                     tmp.insert(i, a)
>                     ret.append(tmp)
>                 return ret
>
>             (a, *b) = seq
>             tmp = permutations(b)
>             tmp = map(lambda x : insertAll(x, a) , tmp)
>
>             return sum(tmp, []) # sum([[1,2,3], [-1,-2,-3]], []) ->
> [1,2,3,-1,-2,-3]
>         except:
>             # no otherwise!
>             pass
>
> Have I got that right? but anyway, there has GOT to be a more pythonic way
> to write that! And I say that because this feels to me like trying to write
> functional code in Python in an unnatural-for-python way, then saying we
> need to add features to python to make that natural.
>
> SoL I think the challenge is:
>
> find some nice compeling examples
> write them in a nice pythonic way
> show us that that these new features would allow a cleaner, more readable
> solution.
>
> Steven did have a nice example of that:
>
> result = (myfile.readlines()
>                  -> map(str.strip)
>                  -> filter( lambda s: not s.startwith('#') )
>                  -> sorted
>                  -> collapse  # collapse runs of identical lines
>                  -> extract_dates
>                  -> map(date_to_seconds)
>                  -> min
>                  )
>
> Though IIUC, the proposal would make that:
>
> result = (myfile.readlines()
>                  -> map(str.strip, _)
>                  -> filter( lambda s: not s.startwith('#'), _ )
>                  -> sorted( _ )
>                  -> collapse( _ )  # collapse runs of identical lines
>                  -> extract_dates( _ )
>                  -> map(date_to_seconds, _)
>                  -> min(_)
>                  )
>
>
> The current Python for that might be:
>
> result = min((date_to_seconds(d) for d in
>                 extract_dates(
>                   collapse(
>                     sorted([s for s in
>                       (s.strip() for line in myfile.readlines)
>                       if not s.startswith]
>                       )))))
>
> Which really does make the point that nesting comprehension gets ugly fast!
>
> So "don't do that":
>
> lines = collapse(sorted((l.strip().split("#")[0] for l in
> myfile.readlines())))
> dates = min((date_to_seconds(extract_date(l)) for l in lines))
>
> or any number of other ways -- clearer, less clear??
>
> -CHB
>
> --
>
> Christopher Barker, Ph.D.
> Oceanographer
>
> Emergency Response Division
> NOAA/NOS/OR&R            (206) 526-6959   voice
> 7600 Sand Point Way NE   (206) 526-6329   fax
> Seattle, WA  98115       (206) 526-6317   main reception
>
> [email protected]
> <javascript:_e(%7B%7D,'cvml','[email protected]');>
>
_______________________________________________
Python-ideas mailing list
[email protected]
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to