AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / user-9840917

myname's questions

Martin Hope
myname
Asked: 2025-04-25 23:30:37 +0800 CST

No Common Lisp, qual é a maneira correta de definir um tipo ou nil em um slot de classe?

  • 6

Tenho uma classe na qual quero que alguns slots sejam nulos quando o objeto for criado, mas eles devem ser configuráveis ​​apenas com objetos de um determinado tipo. Algo como:

(defclass Something ()
  ((foo :initarg :foo
        :type (or character 'nil)
        :initform nil
        :accessor something-foo)))

Se eu disser apenas :type character, ou :type (or character nil), então o SBCL reclama por NILnão ser do tipo de caractere declarado. Se eu disser :type (or character 'nil), então parece que ele aceita caracteres e o tipo de símbolo, já que qualquer símbolo parece ser:

CL-USER> (defvar *foo* (make-instance 'Something))
*FOO*
CL-USER> (setf (something-foo *foo*) 'test)
TEST
CL-USER> (something-foo *foo*)
TEST

Existe uma maneira de afirmar que um slot é nulo ou possui o tipo fornecido? Ou devo simplesmente omitir o especificador de tipo e afirmar o tipo no método acessador ou escritor?

Editar:

Depois de pensar um pouco, talvez a expressão seja: :type characterdeixe-o desvinculado e verifique se o slot está vinculado ou não, em vez de verificar se é nulo ou não nulo?

lisp
  • 2 respostas
  • 40 Views
Martin Hope
myname
Asked: 2024-12-13 18:23:18 +0800 CST

Como defino meu tipo com base na classe para que eu possa usar esse tipo em typecase e expressões relacionadas?

  • 6

Considere isto:

(defclass my-string ()
  ((data :initarg :data :type simple-string)
   (properties :initarg :properties :type interval-tree))
  (:documentation
   "Represents a string with properties."))

Gostaria de usar my-string como um tipo em uma expressão typecase:

(defun upcase (obj)
  (typecase obj
    (my-string (string-upcase (slot-value obj 'data)))
    (string (string-upcase obj))
    (integer (char-upcase (code-char obj)))
    (character (char-upcase obj))
    (otherwise (error "Wrong type argument ~S" obj))))

Eu pensei que classes são tipos, mas obviamente não, já que o acima é um erro do compilador. Então eu declarei um tipo:

(deftype my-string (s) (typep s 'my-string))

que parece que tenho que usar assim (caso contrário, recebo um erro de compilação de que o typedef espera um argumento):

(defun upcase (obj)
  (typecase obj
    ((my-string obj) (string-upcase (slot-value obj 'data)))
    (string (string-upcase obj))
    (integer (char-upcase (code-char obj)))
    (character (char-upcase obj))
    (otherwise (error "Wrong type argument ~S" obj))))

No entanto, o SBCL exclui meu código como inacessível! :-)

Como faço isso? Como declarar corretamente um tipo para uma classe para que eu possa usá-lo em expressões onde declarações de tipo são utilizáveis?

Entendo que posso usar struct em vez de class, nesse caso o compilador gera código para o tipo, e o typecase inicial "simplesmente funciona":

(defstruct my-string
  data properties)

Macroexpandir e olhar o código gerado não me deixou realmente mais esclarecido. Vejo isso:

(SB-C:XDEFUN MY-STRING-P
     :PREDICATE
     NIL
     (SB-KERNEL::OBJECT)
   (TYPEP SB-KERNEL::OBJECT 'MY-STRING))

que faz exatamente o que eu fiz, mas não acho que essa função esteja na peça, ou estou errado? Ou eles de alguma forma associam structs com tipos internamente, ou eu perdi alguma parte relevante do código gerado? Não estou muito familiarizado com tudo isso, então é bem provável também.

Uma pergunta relacionada: qual é a maneira correta de modelar uma classe personalizada que estende um tipo interno como string no CommonLisp? É uma maneira melhor de fazer a composição, como feito em my-string, ou talvez seja melhor herdar de alguma classe de string CL interna? Com ​​base nesta pergunta e respostas do SX , parece-me que a herança não é a melhor maneira de modelar tipos, o que provavelmente é para melhor, já que não gostamos de taxonomias como as conhecidas do Java ou do antigo C++.

Por fim, eu nem precisaria de typecase neste caso se eu fizesse upcase um método genérico que se especializasse nesses tipos, todo o problema desaparece, do que estou totalmente ciente. No entanto, eu gostaria de aprender mais sobre tipos e classes, e como modelar algo como o acima em CL.

Desculpe se for um pouco longo e muitas perguntas reunidas em uma, estou apenas aprendendo isso. Parece que cada pergunta que tenho e experimento para uma resposta abre mais 10 perguntas :).

common-lisp
  • 4 respostas
  • 59 Views
Martin Hope
myname
Asked: 2024-11-06 11:29:19 +0800 CST

Existe uma maneira padrão/portátil de consultar se um símbolo representa uma macro de símbolos?

  • 8

Como o título diz, como posso verificar (programaticamente) de forma portátil (se possível) se um símbolo representa uma macro de símbolos?

CL-USER> (define-symbol-macro some-macro some)
SOME-MACRO
CL-USER> (macro-function 'some-macro)
NIL
CL-USER> (fboundp 'some-macro)
NIL

SBCL tem sb-impl::info:

CL-USER> (describe 'sb-impl::info)
SB-INT:INFO
  [symbol]

INFO names a compiled function:
  Lambda-list: (CATEGORY KIND NAME)
  Declared type: (FUNCTION (T T T) (VALUES T T &OPTIONAL))
  Source file: SYS:SRC;COMPILER;GLOBALDB.LISP

INFO has a compiler-macro:
  Source file: SYS:SRC;COMPILER;EARLY-GLOBALDB.LISP

(SETF INFO) names a compiled function:
  Lambda-list: (NEW-VALUE CATEGORY KIND NAME)
  Declared type: (FUNCTION (T T T T) (VALUES T &OPTIONAL))
  Source file: SYS:SRC;COMPILER;GLOBALDB.LISP

(SETF INFO) has a compiler-macro:
  Source file: SYS:SRC;COMPILER;EARLY-GLOBALDB.LISP

Parece funcionar:

CL-USER> (sb-impl::info :variable :kind 'some-macro)
:MACRO
T

É isso que eles usam no código-fonte para a função 'describe' (eu descobri olhando lá).

Antes disso, eu estava olhando para clhs, mas não encontrei nada. Eu perdi ou não há uma maneira padrão? Existe alguma biblioteca portátil/"trivial" que faça isso?

Editar:

Após uma resposta útil, encontrei um wrapper "trivial" para cltl2 . Parece estar no quicklisp também, então podemos ter além do 'special-operator-p' embutido :

(defun special-variable-p (symbol)
    (multiple-value-bind (info ignore1 ignore2)
        (variable-information symbol)
      (declare (ignore ignore1 ignore2))
      (eq :special info)))

(defun symbol-macro-p (symbol)
    (multiple-value-bind (info ignore1 ignore2)
        (variable-information symbol)
      (declare (ignore ignore1 ignore2))
      (eq :symbol-macro info)))

Na verdade, prefiro um booleano generalizado, parece mais útil, então estou usando isto:

(defun symbol-macro-p (symbol)
  "Return if SYMBOL stands for a symbol macro."
    (multiple-value-bind (info ignore1 ignore2)
        (variable-information symbol)
      (declare (ignore ignore1 ignore2))
      (when (eq :symbol-macro info)
        (multiple-value-bind (expansion ignored)
            (macroexpand symbol)
          (declare (ignore ignored))
          expansion))))

CL-USER> (symbol-macro-p 'some-macro)
SOME
lisp
  • 1 respostas
  • 32 Views
Martin Hope
myname
Asked: 2024-07-24 01:35:21 +0800 CST

Como sombrear de forma programática e portátil um símbolo de uma macro?

  • 6

Este é um pouco embaraçoso, mas estou preso nisso há mais tempo do que gostaria de admitir.

Gostaria de gerar uma macro que sombreie automaticamente um símbolo se ele for encontrado em algum pacote existente. Estou usando apenas o pacote :common-lisp e ocultarei várias funções do padrão.

Anteriormente, mantive uma lista de símbolos sombreados e exportados, mas gostaria de não manter essas listas. Em vez disso, eu preferiria sombrear o símbolo de uma macro, para poder ter a declaração de sombra e de exportação junto com a definição. Parece muito simples, entretanto, seja qual for a maneira que eu o implementei, ou estou violando os bloqueios de pacote, ou meu símbolo é indefinido, ou algo mais. Para começar, aqui está um pacote def:

(in-package :cl-user)

(uiop:define-package :foo-package
  (:nicknames :foo)
  (:use :common-lisp)
  (:shadow #:defun))

(in-package :foo)

A função de teste não faz nada, apenas um pequeno wrapper para o teste:

(defun make-string (length init)
  (cl:make-string length :initial-element init))

Minha primeira tentativa ficou assim:

(cl:defmacro defun (name arglist &optional docstring &rest body)
  `(progn
     (when (symbol-package ',name)
       (shadow ',name))
     (cl:defun ,name ,arglist ,docstring ,@body)
     (export '(,name))))

No entanto, isso resulta em uma violação de bloqueio de pacote com SBCL, portanto, a função shadow obviamente não entra em vigor antes de eu tentar redefinir a função com cl:defun.

Envolvê-lo (eval-when (:compile-toplevel :load-toplevel :execute)para disponibilizá-lo em tempo de compilação não ajudou.

Outra tentativa foi usar um gerador:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (cl:defmacro defun (name args &optional docstring &rest body)
    (macrolet ((export-it (name args &optional docstring &rest body)
                 `(progn
                    (when (symbol-package ',name)
                      (shadow ',name))
                    (cl:defun ,name ,args ,docstring ,@body)
                    (export '(,name) *package*))))
      `(export-it ,name ,args ,docstring ,@body))))

Isso me dá common-lisp:make-string desvinculado:

depurador invocado em um UNBOUND-VARIABLE @10039FFD22 no thread #<THREAD "main thread" RUNNING {10044982F3}>: a variável MAKE-STRING não está associada.

Tentei gerar um lambda e funcall, mas também sem muito sucesso.

Se eu sombrear make-string manualmente de repl: (shadow 'make-string), posso posteriormente redefinir e exportar make-string sem problemas.

Parece que não entendi algo mais fundamental aí.

A propósito, eu estava lendo o artigo de M. Cracauer Compile Time Programming e achei uma boa ideia manter tudo no mesmo lugar, mas acho que minha familiaridade com macros e avaliação de tempo de compilação versus tempo de execução não é onde deveria estar .

Entendo que posso usar coisas específicas do SBCL para remover temporariamente bloqueios de pacotes, mas 'shadow' e 'symbol-package' ou 'find-package' e 'find-symbol' que usei inicialmente para verificar se um símbolo está internado em :common -lisp pacote, deve ser mais portátil.

common-lisp
  • 1 respostas
  • 39 Views

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve