Arc Forumnew | comments | leaders | submitlogin
Ask AF: introduce special syntax for type casting?
3 points by kinnard 29 days ago | 5 comments
Would it be sensible to introduce a special syntaxt for typecasting?

in some languages it's like this

Something like

would be much more succinct than

  (coerce param 'sym)
. . and (coerce) is used often enough for it to matter, no?

Edit: moreso with a list

  '("a" "list" "of" "elements")/sym
is more succinct than

  (map [coerce _ 'sym] '( "a" "list" "of" "elements"))

3 points by rocketnia 28 days ago | link

I almost never use (coerce param 'sym) when I can say sym.param instead. I've always thought Arc doesn't really do enough with the `coerce` function to justify having it in the language; individual functions like `sym` and `string` already do its job more concisely.


In practice when I used to write weakly typed utilities in Arc, I tended to find `zap` very nice:

  (def do-something-with-a-symbol (param)
    (zap sym param)
If you're unfamiliar with `zap`, (zap sym param) is essentially (= param (sym param)).

I prefer strong typing these days, but I've sometimes thought this `zap` technique could be refined to put the coercions in the argument list directly. Arc has (o arg default) for optional arguments, and we could imagine a similar (z coercion arg) for automatically zapping an argument as it comes in:

  (def do-something-with-a-symbol ((z sym param))

Something else that's been on my mind is that it could be useful to have higher-order coercion combinators.

Racket code can use `->` to build a contract for a function out of contracts for its arguments and its result. The result of (-> string? string? symbol?) is a contract that verifies a value is a two-argument function and then replaces it with a function that delegates to that one, but which verifies that the arguments are strings and that the result is a symbol.

The same thing could be done for coercions: The result of (as-> string string sym) could be a coercion function that coerces its argument into a two-argument function that delegates to the original value, but which first coerces the arguments to strings and then coerces the result to a symbol.

  (def as-> args
    (let (result-coercion . arg-coercions) rev.args
      (zap rev arg-coercions)
      (fn (orig)
        (fn args
          (result-coercion:apply orig
            (map (fn (coercion arg) coercion.arg)
              arg-coercions args))))))
  (= symbol+ ((as-> string string sym) +))

  arc> (symbol+ 'foo 'bar)
Similarly, in Racket, `(listof symbol?)` is a contract that checks that a value is a list of symbols, and for coercions we could imagine a corresponding `(aslistof sym)` operation for use in your `(map [coerce _ 'sym] ...)` example.

Sometimes Arc's weak typing suffers from making poor guesses as to whether `nil` is intended as a symbol or as a list (not to mention as a boolean), and it takes some adjusting to work around it:

  arc> (symbol+ 'foo 'nil)
  arc> (symbol+ 'nil 'nil)
  arc> (= symbol+ ((as-> [string:or _ "nil"] [string:or _ "nil"] sym) +))
  #<procedure: as->>
  arc> (symbol+ 'nil 'nil)


2 points by kinnard 28 days ago | link

I overlooked the existence of `sym` which does make my request altogether superfluous. Higher-order coercion combinators will take some digestion on my part!


3 points by akkartik 29 days ago | link

I'm skeptical. Are you doing coercions that often? That seems like bad practice. But if you share a little program or app, that may persuade me otherwise.

For coercions, I usually use the `as` alias:

    (as type expr)
rather than

    (coerce expr 'type)
I find it a lot more convenient because `type` is usually atomic while `expr` can be arbitrarily complex. It makes for a more readable result for the short arguments to come first.

In Anarki, `as` is more common than `coerce`, though we still do a lot of `coerce` that could probably stand to be cleaned up:

    $ grep '[:(]as\>' lib/*.arc |wc -l
    $ grep '[:(]coerce\>' lib/*.arc |wc -l


2 points by kinnard 28 days ago | link



3 points by akkartik 29 days ago | link

> '("a" "list" "of" "elements")/sym => (map [coerce _ 'sym] '( "a" "list" "of" "elements"))

That's starting to get outside the look and feel of a Lisp. Usually you look to the start of any form to see what it is. The fact that quoted lists can get a post-processor feels more like Forth.

And the `/sym` somehow now has to automatically do different things for a list or other expression? That feels more like APL than Lisp.