Arc Forumnew | comments | leaders | submitlogin
Mapping over a string is required to produce a string
3 points by zackman 5947 days ago | 5 comments
I noticed that mapping over a string is broken because it produces only a string instead of a list. In other words, (map [coerce _ 'int] "foo") fails. I'm pretty sure Arc inherits this from Scheme, given the error message.

  (map [coerce _ 'int] "foo")
  Error: string-set!: expects type <character> as 3rd argument, given: 102.
Here's what I'd like to see work:

  (map [coerce _ 'int] "foo")
  => '(102 111 111)
  (map [coerce _ 'char] '(102 111 111))
  => "foo"
But I'd settle for the first one. The second I think is impossible to produce in a dynamically typed language because you never know what a function will return:

  (map [and (> (coerce _ 'int) 110) _] "foo")


3 points by ndanger 5946 days ago | link

Strings aren't just lists of characters:

    arc> (map [coerce _ 'int] '(#\f #\o #\o))
    (102 111 111)
    arc> (map [coerce _ 'int] (coerce "foo" 'cons))
    (102 111 111)
    arc> (map [coerce _ 'char] '(102 111 111))
    (#\f #\o #\o)
    arc> (string (map [coerce _ 'char] '(102 111 111)))
    "foo"
To unify strings and lists of chars I think you'd need a way to specify encodings (well, once Arc is worried about that sort of thing).

-----

2 points by randallsquared 5947 days ago | link

Producing the kind of sequence it was given is not what I'd call broken. Additionally, your

    (map [coerce _ 'int] "foo")
    => '(102 111 111)
canonicalizes what I believe is an onion: strings that are transparently byte vectors.

-----

2 points by pg 5947 days ago | link

You have to pick the type of the value based on one of the arguments. It seems cleaner to do it based on the value of the second rather than the values returned by the first when called.

-----

2 points by knome 5946 days ago | link

Why not have the value always be a list? Then you could do this :

    (def stringize ( args ) (apply string args))
    (stringize:map [coerce _ 'int] "test")

-----

1 point by zackman 5946 days ago | link

A couple more comments:

(1) Upon reading arc.arc, I noticed that strings not being lists is a compromise, implying that whole set of problems may go away at some point.

(2) "If you want Haskell, you know where to find it". I really do think that the Right Thing is for the list to be built of the return type of first function. But that is impossible in a dynamically typed language so the Right Thing is probably the type of the sequence map was given.

However, from a pragmatic standpoint, I've more often needed to map the characters of a string to something else. I know this because most Scheme code where I map over a string looks like this: (map (lambda (c) (char->integer c)) (string->list "foo"))

In the PLT standard collects, it looks like about it's about half and half, though; perhaps a few more uses of map in which the return type is not ultimately a string.

-----