Open maweki opened 8 years ago
Interesting idea, although a little hard to implement because failed assignments throw rather generic ValueErrors and TypeErrors -- simply making (a = b) => c
equivalent to
(except
err => a = b
err :: ValueError or err :: TypeError => False
err is None => True) => c
would catch a lot more than needed.
As for making parentheses optional, that would also affect how a = b => c
is parsed outside of if
s, so not feasible. (=>
being an operator on its own is a thing because if x =>
followed by an indented block behaves weirdly. Frankly, if
, except
, and =>
are all poorly implemented and need to be redesigned.)
Well, I think this would be correct.
if
a[1] => something
otherwise => False
I would be fine with going to the otherwise-case instead of getting an error if the element has not getitem or if we get a key-error. There is no nice way to catch an exception in the condition of the if
-construct anyways.
So as I see it, any exception in the condition-clauses should just make the condition evaluate to false. I see this could be a bit of an issue since if
could return None
if none of the cases matches so one idea to fix that would be to throwing a "non-exhaustive patterns"-like error that could be nicely catched with an outside except.
So as I see it, any condition => block
in the if
-construct should be equivalent to
(except
err => condition
err :: Exception => False
err is None => True) => block
Not sure hiding all exceptions in conditions is a good idea. A condition is an arbitrary expression, possibly with side effects, etc. Most likely cause of an exception is not a failed pattern match, and simply ignoring an error is probably not the correct way of handling it.
Anyway, I've special-cased (a = b) => c
where a = b
is an unpacking assignment, so the pattern-matching aspect of your proposal should work, at least. (It works by checking that b
is an iterable of correct length before performing the actual assignment, so no exceptions other than those during UNPACK_SEQUENCE are caught.)
ignoring an error is probably not the correct way of handling it
I don't think I agree.
Given (3) it is a common pattern to just get an attribute or an item or unpack something and catch an exception. But given (2) there is no good way to catch that exception within multiple conditions. The otherwise keyword already is (at least semantically) a fallback if all condition-statements were "false-ish" but given (1) is still not executed. Also, the statement in the condition should (usually) not have side-effects given the pythonic pattern of either having side-effects or returning a value but not both.
Anyways, thank you for the unpacking-fix. It's greatly appreciated. :)
What I forgot to ask: does the fix work with an arbitrary nesting (it does in python)?
([x,*xs],[y, *ys]) = (x', y')
Ah. Damn. No, it does not. Gonna have to fix that, I guess...
This would be my test-cases, reimplementing zip and a list-constructor:
zip' = x' y' -> if
([x, *xs], [y, *ys] = x', y') => yield (x, y)
yield from $ zip' xs ys
otherwise => yield from ()
mylist = x' -> if
([] = x') => []
([x, *xs] = x') => [x] + mylist xs
print $ list $ zip' ( range 3 ) ( range 7 )
print $ mylist $ range 6
For the first one I get ValueError: need more than 0 values to unpack
and for the latter ValueError: too many values to unpack (expected 0)
. The exception is not caught
The first test isn't actually valid -- you have a call to yield
followed by an indented block, so the statement is equivalent to yield (x, y) (yield from $ zip' xs ys)
. A correct version would be
zip' = x' y' -> if
([x, *xs], [y, *ys] = x', y') =>
yield (x, y)
yield from $ zip' xs ys
otherwise => yield from ()
Other than that, both seem to work on my machine. However, Arch Linux ships Python 3.5 in its repositories, and I was too lazy to compile 3.4 and 3.6, so only the cpython-35 bundle actually contains the changes. Try running python3 -m dg -b
first if you're using a different version.
Thank you, python3 -m dg -b
fixed the issue. And also thank you for the fixed test-case.
I will present dogelang at a local Haskell conference and "pattern matching but not quite" is a fine addition to the talk :)
tuple unpacking in python is very useful. One can unpack a list into
head, *tail = somelist
and it looks a bit like haskell'scase x' of x:xs
. If exceptions in the if-cases were considered as false instead of being thrown, we could have a function that looked like thisone could throw an exception if none of the cases fits.
This would make the language a bit more useful which might be unwanted. But it would also be a bit like pattern-matching but not quite, throwing haskell-people off even more.
If this were to work, having tuple unpacking in the case without the brackets would be even nicer. But one thing at a time.