Есть ли другие языки помимо D с помехами если?

Ctrl+f тогда отмечают флажок "Regular expressions". От этого можно искать с регулярными выражениями, но еще более мощно, можно включать соответствия группы в замещающую строку (1$, 2$, и т.д., или 0$ для целого соответствия).

13
задан Mechanical snail 22 August 2012 в 20:36
поделиться

2 ответа

Any language with real macros has a form of static if. For instance Lisp and Nemerle let you construct the code that a macro expands to using programming constructs like 'if' and for-loops. Those are essentially compile-time decisions and let you do something similar to static if. In the case of Nemerle macros are basically plug-ins to the compiler that are executed at compile-time.

In C++ there's boost MPL library which has a kind of static if that can be used to choose between two types. You could put some code inside the two types in a run() member and get something kinda similar, but with very cumbersome syntax.

For example with Boost MPL you could do something like this:

struct float_impl { 
    static void run() { /* float case code */ }
}
struct int_impl { 
    static void run() { /* int case code */ }
}

typedef typename if_<
          is_same<T, float>
        , float_impl
        , int_impl
        >::type impl_t;
impl_t::run();

In D that'd be:

static if(is(T == float)) {
     /* float code */
}
else {
     /* int code */
}
10
ответ дан 2 December 2019 в 00:31
поделиться

For a "language's awareness of code", there's no better I've seen than Lisp and its macro facility -- specifically, Common Lisp. But the trade there is that most of the time an object's type is not known at compile time or macroexpansion time. For literals, the types are known, so you can find examples of aggressive macros that test to see if an object is a literal and, if so, treat it one way -- maybe based on its type -- and otherwise prepare the detected variable for run-time type inspection.

Here's an example I adapted from the CLLIB library (part of the CLOCC library) several years ago. The goal is to provide functions that will chop a prefix string off of some other string with a matching prefix. The prefix may be known at macroexpansion time or it may not. If it is, we can an optimization: compute the prefix's length first and embed it as a literal, so that it's not recomputed on each call to the generated function. The macro is daunting at first, but the actual generated code is small.

(defmacro after-prefix-core (comparison-op prefix string &optional length)
  "Similar to cllib:string-beg-with-cs."
  (flet ((chop (prefix prefix-length string string-length)
           `(when (and (>= ,string-length ,prefix-length)
                       (,comparison-op ,prefix ,string :end2 ,prefix-length))
              (subseq ,string ,prefix-length ,string-length))))
    (let* ((gstring (gensym "STRING-"))
           (gstring-length (gensym "STRING-LENGTH-")))
      `(let* ((,gstring ,string)
              (,gstring-length ,(or length `(length ,gstring))))
         ,(if (stringp prefix)
              ;; Constant -- length known at expansion time.
              (let ((prefix-length (length prefix)))
                (chop prefix prefix-length gstring gstring-length))
              ;; Other form -- length not known at expansion time.
              (let ((gprefix (gensym "PREFIX-"))
                    (gprefix-length (gensym "PREFIX-LENGTH-")))
                `(let* ((,gprefix ,prefix)
                        (,gprefix-length (length ,gprefix)))
                   ,(chop gprefix gprefix-length gstring gstring-length))))))))


(defmacro after-prefix (prefix string &optional length)
  "Similar to cllib:string-beg-with."
  `(after-prefix-core string-equal ,prefix ,string ,length))


(defmacro after-prefix-cs (prefix string &optional length)
  "Similar to cllib:string-beg-with-cs."
  `(after-prefix-core string= ,prefix ,string ,length))

See the form

(if (stringp prefix)

in the middle? That's inspecting the first argument at macroexpansion time and, depending on whether the argument is a literal or symbol, its type may or may not be known. If the type is a symbol, we assume that we should wait until run time to reconsider it as a variable pointing to some other value.

Here's the expansion for the form (after-prefix foo bar):

(LET* ((#:STRING-5340 BAR) (#:STRING-LENGTH-5341 (LENGTH #:STRING-5340)))
  (LET* ((#:PREFIX-5342 FOO) (#:PREFIX-LENGTH-5343 (LENGTH #:PREFIX-5342)))
    (WHEN
        (AND (>= #:STRING-LENGTH-5341 #:PREFIX-LENGTH-5343)
             (STRING-EQUAL #:PREFIX-5342 #:STRING-5340 :END2 #:PREFIX-LENGTH-5343))
      (SUBSEQ #:STRING-5340 #:PREFIX-LENGTH-5343 #:STRING-LENGTH-5341))))

Note that the variable #:PREFIX-LENGTH-5343 is bound to the computed length of FOO, bound here to variable #:PREFIX-5342.

Now look at the expansion for the form (after-prefix "foo" bar), where the prefix is now a string literal:

(LET* ((#:STRING-5463 BAR) (#:STRING-LENGTH-5464 (LENGTH #:STRING-5463)))
  (WHEN (AND (>= #:STRING-LENGTH-5464 3) (STRING-EQUAL "foo" #:STRING-5463 :END2 3))
    (SUBSEQ #:STRING-5463 3 #:STRING-LENGTH-5464)))

Now there's no computing the length of "foo"; it's inlined as 3.

It may seem like too much work in this example, but being able to do such things is a good power to have, as your question opines.

2
ответ дан 2 December 2019 в 00:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: