why does “(def vowel? (set ”aeiou“))” work?

前端 未结 2 1112
慢半拍i
慢半拍i 2021-02-13 05:43

I\'m taking a look at the excellent Clojure tutorial here. In one of the examples it has Clojure code along the following lines:

(def vowel? (set \"aeiou\"))


        
相关标签:
2条回答
  • 2021-02-13 06:02

    Aha! I ended up finding it out myself. It doesn't actually return true or false, rather it returns the first occurrence in the set, or nil if it doesn't occur.

    And because you can use this as a condition (nil being handled as false, and non-nil as true), this works as a nice little hack for checking if a string contains a letter.

    (vowel? (first "abc")) ; => "a"
    (vowel? (first "cba")) ; => nil
    
    (if (vowel? (first "abc"))
           (println "yay")
           (println "oops"))  ; => "yay"
    
    0 讨论(0)
  • 2021-02-13 06:18

    This is perfectly analogous to how maps (the most natural objects in Clojure) work. When the map is called as a function, it works as a mapping:

    user=> (def ob {:foo "bar", :bar :baz, :qwerty 42})
    #'user/ob
    user=> (ob :foo)
    "bar"
    

    So it makes sense that a Clojure set can be called as a function, and will work as a membership test. By the way, if you use keywords (those things that start with a colon) as the keys of a mapping, they also work as similar functions, so you can do

    user=> (:bar ob)
    :baz
    

    and even the same thing with sets of keywords:

    user=> (def vowel-keywords (set [:a :e :i :o :u]))
    #'user/vowel-keywords
    user=> (:a vowel-keywords)
    :a
    user=> (:b vowel-keywords)
    nil
    

    But, again, this latter trick only works with keywords, not anything else that you might use as keys in a mapping or members in a set.

    0 讨论(0)
提交回复
热议问题