Arc Forumnew | comments | leaders | submitlogin
2 points by rocketnia 5065 days ago | link | parent

In Penknife I've been mulling over 'testify a lot, trying to figure out whether there's a way to stop special-casing the 'fn type or to make it an everyday coercion function by introducing a 'test type or renaming it to 'fnify. I think I have the start of some answers....

Recently I posted an example utility, 'copdate, that acted exactly like 'copy but called functions on the existing values to get the replacement ones. http://arclanguage.org/item?id=13652

It would be cool if 'copy itself did that. Essentially we'd check the replacement value, and if it was a function, we'd treat it as a conversion function, and otherwise we'd just use it directly. This check could be done by a satellite utility:

  (def conversionify (x)
    (case type.x fn x [do x]))
This is just as arbitrary about the 'fn type as 'testify is, and it has just as much right (IMO) to be called 'fnify. But now we have two cousins, so we can extract their common warts into another function:

  (def abehavior (x)
    (isa x 'fn))
  
  (def testify (x)
    (check x abehavior [iso x _]))  ; not using 'is here!
  
  (def conversionify (x)
    (check x abehavior [do x]))
This 'abehavior utility is naturally extensible. Its default behavior can be nil, and each of its extensions can return t under new conditions. The question "Is this type of value supposed to be idiomatic for specifying custom behaviors for everyday Arc utilities?" isn't hard to answer. A behavior will need to have a 'defcall implementation anyway, so that's a good way to decide (but not perfect, 'cause indexable data structures use 'defcall too).

  (def abehavior (x)
    nil)
  
  (made-up-rule-definer abehavior (x) (isa x 'fn)
    t)
Also, 'testify and 'conversionify have a kinda nice common semantics: Each of them coerces to the behavior "type" based on its own idea of what a normal behavior is.

Is there a way to expose a design flaw in between 'abehavior and the places it's used? What if there's a type of value that's especially good at encoding tests or conversions, but not idiomatic for specifying callbacks? In fact, you've already mentioned one:

if it sees a list it checks for membership

I totally agree. I really like how Groovy's switch statements have that behavior. XD However, what's to say a list is an idiomatic way to give a list of options but a string isn't? Well, maybe I'd go with another function:

  (def acontainer (x)
    nil)
  
  (made-up-rule-definer acontainer (x) alist.x
    t)
  
  (def testify (x)
    [iso x _])
  
  (made-up-rule-definer testify (x) abehavior.x
    x)
  
  (made-up-rule-definer testify (x) acontainer.x
    [mem-not-using-testify _ x])
However nice (or paranoid ^^ ) this setup might be, what happens if you're looking for nil? Should nil be interpreted as an unsatisfiable condition? Well, that's probably not too bad; it's up to the utility designer to say what nil does, and we're in that realm at the moment. People will just have to say (some [iso x _] foo) instead of (some x foo) if x could be nil, even if they don't expect x to be any other kind of container or behavior.

Hopefully this rant has helped you nearly as much as it's helped me. :-p