Different behavior racket/base vs. racket/hash

How come:

#lang racket
(define h (make-hash
           (list
            (list "a" 1)
            )
           )
)
(hash-ref h "a")

returns '(1) [a list of one element], but in Advanced Student Language:

(define h (make-hash
           (list
            (list "a" 1)
            )
           )
)
(hash-ref h "a")

returns 1 [a simple value]?
Is there any way to get the latter after using (require racket) (because I need other libraries from racket)?

Many thanks in advance,
--Allan

  1. I quickly checked the relevant parts of the ASL implementation and found a note that I left behind years ago when I discovered how people had added hashes to ASL:

;; *****************************************************************************
;; MF: This design decision breaks one of the fundamental design guidelines for
;; the teaching languages but it clearly has been in place for years. No going back.
;; The correct design would have modified hash-ref and other observers of HASHes.
;; *****************************************************************************

  1. This brings me to issue a bit of a warning: ASL is essentially unsupported. Once we gave up on ASL for HtDP/2e, it became an experimentation language for certain courses.

  2. If your question is whether you can get the hash-ref from racket into your code, adding (require racket) near the top will work.

  3. If this is supposed to go to students, I recommend the creation of a teach pack that students then require. That way you can manage what you want to include from racket and what you want to exclude plus functions from other libs.

Many thanks for you quick response.

I think we will just go with writing our own hash-ref that simply does a first on the return value from the original hash-ref.
Unless that is a bad idea?

I am confused now. I thought you wanted racket's behavior in #lang htdp/asl.

Are you asking for something like

(define (hash-ref/first h x)
  (define r (hash-ref h x))
  (if (cons? r) (first r) r))

FWIW, In Racket the association list for creating hashes,

  (list
   (cons key1 value1)
   (cons key1 value2)
   ...)

is not a working program in *SL because cons works on lists, not arbitrary pairs. Either *SL has to use list of two-element lists or creates its own datatype for pairs:

#lang htdp/isl+

(list
 (cons 'key1 'value1)
 (cons 'key2 'value2))

;; . . cons: second argument must be a list, but received 'key1 and 'value1
;; >

(Thanks @shhyou I should have explained my warning note in the ASL module more clearly.)

If you create a racket-minus.rkt like this:

#lang racket
(provide (except-out (all-from-out racket)
                     make-hash))

then your main file can do:

#lang htdp/asl
(require "racket-minus.rkt")
(define h
  (make-hash (list (list "a" 1))))
(check-expect (hash-ref h "a") 1)

In most Racket-family languages, I would tell you to write (require (except-in racket make-hash)), but the variant of require from #lang htdp/asl does not allow most require subforms:

require: expected a module name as a string, a `lib' form, or a `planet' form, found a part in: (except-in racket make-hash)

Tangentially, the error message is not accurate, given that e.g. (require 2htdp/image) is allowed.


More broadly, I would be concerned that (require racket) would have confusing unintended consequences, since it will shadow so many bindings from ASL, including define, lambda (adding Racket's optional and keyword arguments), and implicit bindings (e.g. #%app and #%datum, which control the meaning of function application and of literal data, respectively). I think you would be better off explicitly importing only what you need from Racket. (If you really wanted to, you could teach in #lang racket after/instead of ASL, but I found the teaching languages very helpful as a student.)

Concretely, along the lines of @shhyou's examples, (require racket) would shadow the definition of cons from ASL, so you could instruct students to create hash tables with Racket-style association lists (but I am not claiming this would be good pedagogy):

#lang htdp/asl
(require racket)
(define h
  (make-hash (list (cons "a" 1))))
(check-expect (hash-ref h "a") 1)