{"id":16164614,"url":"https://github.com/kisom/cl-contracts","last_synced_at":"2026-01-21T01:01:55.783Z","repository":{"id":29911832,"uuid":"33457666","full_name":"kisom/cl-contracts","owner":"kisom","description":"Common Lisp contracts","archived":false,"fork":false,"pushed_at":"2015-04-05T22:55:09.000Z","size":100,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-07T04:48:42.015Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kisom.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-04-05T22:41:19.000Z","updated_at":"2020-03-08T13:37:09.000Z","dependencies_parsed_at":"2022-07-27T23:48:52.211Z","dependency_job_id":null,"html_url":"https://github.com/kisom/cl-contracts","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kisom/cl-contracts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kisom%2Fcl-contracts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kisom%2Fcl-contracts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kisom%2Fcl-contracts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kisom%2Fcl-contracts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kisom","download_url":"https://codeload.github.com/kisom/cl-contracts/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kisom%2Fcl-contracts/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28620572,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T23:49:58.628Z","status":"ssl_error","status_checked_at":"2026-01-20T23:47:29.996Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-10T02:47:15.625Z","updated_at":"2026-01-21T01:01:55.762Z","avatar_url":"https://github.com/kisom.png","language":"Common Lisp","funding_links":[],"categories":[],"sub_categories":[],"readme":"#+TITLE: cl-contracts\n#+AUTHOR: K. Isom \u003ckyle@metacircular.net\u003e\n\n* Introduction\n\n  This pacakge is a basic example of how to implement contracts\n  in Common Lisp. A contract is a specification of the behaviour\n  of a function, and in the case of this package, are implemented\n  as assertions.\n\n  A simple contract definition might look like the following:\n\n#+BEGIN_EXAMPLE\n(defcontract upcase (s)\t\t; function name and arguments\n             #'stringp\t\t; argument contract\n             (lambda (in out)   ; output contract\n                (declare (ignore in))\n                (stringp out))\n             (string-upcase s)) ; function body\n\n#+END_EXAMPLE\n\n  This defines a function named ~upcase~ that takes a single argument\n  ~s~. The argument contract asserts that its input will be a string\n  and that its output will also be a string. Note that the argument\n  contract takes as many arguments as the function arguments: ~upcase~\n  is a function of one argument (~s~), and ~#'STRINGP~ is a function\n  of one argument.\n\n  Perhaps more useful is to observe the macro expansion of the above\n  example:\n\n#+BEGIN_EXAMPLE\nCL-CONTRACTS\u003e (macroexpand-1\n '(defcontract upcase (s)\n   #'stringp\t\t; argument contract\n   (lambda (in out)   ; output contract\n     (declare (ignore in))\n     (stringp out))\n   (string-upcase s)))\n(DEFUN UPCASE (S)\n  (ASSERT (FUNCALL #'STRINGP S))\n  (LET ((#:G1029 (PROGN (STRING-UPCASE S))))\n    (ASSERT\n     (FUNCALL (LAMBDA (IN OUT) (DECLARE (IGNORE IN)) (STRINGP OUT)) S #:G1029))\n    #:G1029))\nT\n#+END_EXAMPLE\n\n* Variations on a theme: string upcasing\n\n  Here's a simple exploration of what ~defcontract~ looks like in\n  use. I'll begin with the simplest possible contract: no contract.\n\n#+BEGIN_EXAMPLE\n(defcontract upcase (s)\n    nil nil ; no contracts\n  (string-upcase s))\n#+END_EXAMPLE\n\n  The nil contracts means that no assertions are inserted into the\n  resulting function.\n\n#+BEGIN_EXAMPLE\nCL-USER\u003e (macroexpand-1\n\t       '(defcontract upcase (s)\n                    nil nil ; no contracts\n                    (string-upcase s)))\nCL-USER\u003e (DEFUN UPCASE (S)\n  NIL\n  (LET ((#:G1035 (PROGN (STRING-UPCASE S))))\n    NIL\n    #:G1035))\nT\n#+END_EXAMPLE\n\n#+BEGIN_EXAMPLE\nCL-USER\u003e (upcase \"hello, world\")\n\"HELLO, WORLD\"\nCL-USER\u003e (upcase 1)\n; Evaluation aborted on #\u003cTYPE-ERROR expected-type:\n             (OR (VECTOR CHARACTER) (VECTOR NIL) BASE-STRING SYMBOL CHARACTER)\n             datum: 1\u003e.\n#+END_EXAMPLE\n\n  When it fails, it fails when it actually attempts to call the\n  ~string-upcase~ function; while no damage is done here, it's\n  possible that providing the wrong type could be damaging in other\n  cases.\n  \n  A simple argument checker might check that the function received\n  only a string argument.\n\n#+BEGIN_EXAMPLE\n(defcontract upcase% (s)\n    #'stringp ; argument checker\n    nil       ; still not checking the output\n  (string-upcase s))\n\n(macroexpand-1 '(defcontract upcase% (s)\n                                  #'stringp ; argument checker\n                                  nil       ; still not checking the output\n                                 (string-upcase s)))\n(DEFUN UPCASE% (S)\n  (ASSERT (FUNCALL #'STRINGP S))\n  (LET ((#:G1036 (PROGN (STRING-UPCASE S))))\n    NIL\n    #:G1036))\nT\n#+END_EXAMPLE\n\n  The function body now has an argument contract assertion in place,\n  as seen in the expansion.\n\n#+BEGIN_EXAMPLE\nCL-USER\u003e (upcase% \"hello, world\")\n\"HELLO, WORLD\"\nCL-USER\u003e (upcase% 1)\n; Evaluation aborted on #\u003cSIMPLE-ERROR \"~@\u003cThe assertion ~S failed~:[.~:; ~\n                                    with ~:*~{~{~S = ~S~}~^, ~}.~]~:@\u003e\" {10059E0E93}\u003e.\n#+END_EXAMPLE\n\n  The argument failed to uphold the argument contract, and the\n  function signalled an assertion failure.\n  \n  The function that checks the output receives a copy of the\n  arguments and the result of the body. This means that it can\n  compare the arguments against the output to verify that the\n  correct behaviour occurred.\n\n#+BEGIN_EXAMPLE\n(defcontract upcase%% (s)\n    #'stringp               ; looking for strings\n    (lambda (in out)        ; always produce a string\n      (declare (ignore in))\n      (stringp out))\n  (string-upcase s))\n#+END_EXAMPLE\n\n  In the previous example, the output contract will always be\n  upheld. We can see that because ~string-upcase~ always returns a\n  string, and we always get a string to ~string-upcase~, the\n  function will always return a string.\n  \n  The fact that the output contract checker receives the arguments\n  as well as the output means that the function can be verified to\n  always return a string that is the same length as the input\n  string.\n\n#+BEGIN_EXAMPLE\n(defun string-output-contract (in out)\n    (and (stringp out)\n\t (eql (length in)\n\t      (length out))))\n\n(defcontract upcase%%% (s)\n    #'stringp\n    #'string-output-contract\n  (string-upcase s))\n#+END_EXAMPLE\n\n  The previous function will always satisfy this contract, but the\n  following will always fail.\n\n#+BEGIN_EXAMPLE\n(defcontract upcase%%%% (s)\n  #'stringp\n  #'string-output-contract\n  (let ((s* (string-upcase s)))\n    (concatenate 'string s* s*)))\n#+END_EXAMPLE\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkisom%2Fcl-contracts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkisom%2Fcl-contracts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkisom%2Fcl-contracts/lists"}