smullyan 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dc72b10962093f30311be948daf19e7fd1d4d4326109ea4648f3f2d7da9a2221
4
+ data.tar.gz: 666b61abefb823b327391786d60ccbe150c7e3328b5235f52cfb75318a472387
5
+ SHA512:
6
+ metadata.gz: 5ca24e8d12f163e6d118d66bd7b4e85c8a1eada06b8cb99076ec1c1479cbc098456932e0b7350d197cbd407af726509057aba6d438ceba801fcc08bfa9b636dc
7
+ data.tar.gz: e8bfe5eb34b6d3e6affc0c79fde8937c8625dc7a60a9884997b220ecc46173518a725f070678eb6a792cee3ced000c40cffc90a7f33db083974314311c7898ad
data/CLAUDE.md ADDED
@@ -0,0 +1,67 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ This is a Ruby gem implementing combinators from Raymond Smullyan's "To Mock a Mockingbird". The project uses:
8
+ - Ruby (>= 2.7.0)
9
+ - Minitest for testing
10
+ - RuboCop for code linting
11
+ - Bundler for dependency management
12
+
13
+ ## Common Development Commands
14
+
15
+ ```bash
16
+ # Install dependencies
17
+ bundle install
18
+
19
+ # Run tests
20
+ bundle exec rake test
21
+ # or
22
+ bundle exec rake
23
+
24
+ # Run a specific test file
25
+ bundle exec ruby test/test_ski.rb
26
+
27
+ # Run linting
28
+ bundle exec rubocop
29
+
30
+ # Run tests and linting (default task)
31
+ bundle exec rake
32
+
33
+ # Build the gem
34
+ bundle exec rake build
35
+
36
+ # Install gem locally
37
+ bundle exec rake install
38
+
39
+ # Release to RubyGems (requires permissions)
40
+ bundle exec rake release
41
+ ```
42
+
43
+ ## Project Structure
44
+
45
+ - `lib/smullyan.rb` - Main module with combinator implementations (Birds module)
46
+ - `lib/smullyan/version.rb` - Version constant
47
+ - `test/test_smullyan.rb` - Minitest test files
48
+ - `smullyan.gemspec` - Gem specification
49
+ - `Rakefile` - Rake tasks for testing and building
50
+
51
+ ## Architecture Notes
52
+
53
+ The gem implements combinators from combinatory logic, each with both a letter name and a bird name from Smullyan's book:
54
+
55
+ ### Core SKI Combinators:
56
+ - **S combinator (Starling)**: `S x y z = x z (y z)`
57
+ - **K combinator (Kestrel)**: `K x y = x`
58
+ - **I combinator (Identity/Idiot)**: `I x = x`
59
+
60
+ ### Additional Combinators:
61
+ - **B combinator (Bluebird)**: `B x y z = x (y z)` - function composition
62
+ - **C combinator (Cardinal)**: `C x y z = x z y` - argument flip
63
+ - **W combinator (Warbler)**: `W x y = x y y` - duplication
64
+ - **M combinator (Mockingbird)**: `M x = x x` - self-application
65
+ - **Y combinator (Why/Sage)**: Fixed-point combinator for recursion
66
+
67
+ These are implemented as Ruby lambda functions in the `Smullyan::Birds` module, with both single-letter names (S, K, I, etc.) and bird names (Starling, Kestrel, Identity, etc.) available.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Phil Crissman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # Smullyan
2
+
3
+ A Ruby implementation of combinators from Raymond Smullyan's "To Mock a Mockingbird".
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'smullyan'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install smullyan
20
+
21
+ ## Usage
22
+
23
+ ```ruby
24
+ require 'smullyan'
25
+
26
+ # Using the classic SKI combinators
27
+ s = Smullyan::Birds::S
28
+ k = Smullyan::Birds::K
29
+ i = Smullyan::Birds::I
30
+
31
+ # Or use the bird names!
32
+ kestrel = Smullyan::Birds::Kestrel # K combinator
33
+ starling = Smullyan::Birds::Starling # S combinator
34
+ mockingbird = Smullyan::Birds::Mockingbird # M combinator
35
+
36
+ # Example: Identity function derived from S and K
37
+ identity = s.call(k).call(k)
38
+ identity.call(42) # => 42
39
+
40
+ # Example: Function composition with the Bluebird
41
+ bluebird = Smullyan::Birds::Bluebird
42
+ double = ->(x) { x * 2 }
43
+ increment = ->(x) { x + 1 }
44
+ double_after_increment = bluebird.call(double).call(increment)
45
+ double_after_increment.call(5) # => 12
46
+
47
+ # Example: Y combinator for recursion
48
+ why = Smullyan::Birds::Why
49
+ factorial = why.call(->(f) {
50
+ ->(n) { n <= 1 ? 1 : n * f.call(n - 1) }
51
+ })
52
+ factorial.call(5) # => 120
53
+ ```
54
+
55
+ ## Development
56
+
57
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
58
+
59
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
60
+
61
+ ## Contributing
62
+
63
+ Bug reports and pull requests are welcome on GitHub at https://github.com/philcrissman/smullyan.
64
+
65
+ ## License
66
+
67
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb", "test/**/test_*.rb"]
10
+ end
11
+
12
+ require "rubocop/rake_task"
13
+
14
+ RuboCop::RakeTask.new
15
+
16
+ task default: %i[test rubocop]
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "starling"
4
+ require_relative "kestrel"
5
+
6
+ module Smullyan
7
+ module Birds
8
+ # The Bluebird - function composition
9
+ # Bluebird x y z = x (y z)
10
+ # Can be derived as: B = S (K S) K
11
+ Bluebird = S.call(K.call(S)).call(K)
12
+
13
+ # Direct implementation for comparison/efficiency
14
+ Bluebird_direct = ->(x) { ->(y) { ->(z) { x.call(y.call(z)) } } }
15
+
16
+ # Traditional combinator name
17
+ B = Bluebird # B combinator
18
+ B_direct = Bluebird_direct
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "starling"
4
+ require_relative "bluebird"
5
+ require_relative "kestrel"
6
+
7
+ module Smullyan
8
+ module Birds
9
+ # The Cardinal - flips the order of arguments
10
+ # Cardinal x y z = x z y
11
+ # Can be derived as: C = S (B B S) (K K)
12
+ Cardinal = S.call(B.call(B).call(S)).call(K.call(K))
13
+
14
+ # Direct implementation for comparison/efficiency
15
+ Cardinal_direct = ->(x) { ->(y) { ->(z) { x.call(z).call(y) } } }
16
+
17
+ # Traditional combinator name
18
+ C = Cardinal # C combinator
19
+ C_direct = Cardinal_direct
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smullyan
4
+ module Birds
5
+ # The Identity bird - returns its argument unchanged
6
+ # Identity x = x
7
+ Identity = ->(x) { x }
8
+
9
+ # Traditional combinator names
10
+ I = Identity # I combinator
11
+ Idiot = Identity # Alternative name from Smullyan's book
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smullyan
4
+ module Birds
5
+ # The Kestrel - returns the first of two arguments
6
+ # Kestrel x y = x
7
+ Kestrel = ->(x) { ->(y) { x } }
8
+
9
+ # Traditional combinator name
10
+ K = Kestrel # K combinator
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "cardinal"
4
+ require_relative "bluebird"
5
+ require_relative "mockingbird"
6
+
7
+ module Smullyan
8
+ module Birds
9
+ # The Lark - applies first argument to result of second argument applied to itself
10
+ # Lark x y = x (y y)
11
+ # Can be derived as: L = C B M
12
+ Lark = C.call(B).call(M)
13
+
14
+ # Direct implementation for comparison/efficiency
15
+ Lark_direct = ->(x) { ->(y) { x.call(y.call(y)) } }
16
+
17
+ # Traditional combinator name
18
+ L = Lark # L combinator
19
+ L_direct = Lark_direct
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "starling"
4
+ require_relative "identity"
5
+
6
+ module Smullyan
7
+ module Birds
8
+ # The Mockingbird - self-application
9
+ # Mockingbird x = x x
10
+ # Can be derived as: M = S I I
11
+ Mockingbird = S.call(I).call(I)
12
+
13
+ # Direct implementation for comparison/efficiency
14
+ Mockingbird_direct = ->(x) { x.call(x) }
15
+
16
+ # Traditional combinator name
17
+ M = Mockingbird # M combinator
18
+ M_direct = Mockingbird_direct
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smullyan
4
+ module Birds
5
+ # The Starling - distributes its third argument to both its first and second
6
+ # Starling x y z = x z (y z)
7
+ Starling = ->(x) { ->(y) { ->(z) { x.call(z).call(y.call(z)) } } }
8
+
9
+ # Traditional combinator name
10
+ S = Starling # S combinator
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "cardinal"
4
+ require_relative "starling"
5
+ require_relative "identity"
6
+
7
+ module Smullyan
8
+ module Birds
9
+ # The Warbler - duplicates its argument
10
+ # Warbler x y = x y y
11
+ # Can be derived as: W = C S I
12
+ Warbler = C.call(S).call(I)
13
+
14
+ # Direct implementation for comparison/efficiency
15
+ Warbler_direct = ->(x) { ->(y) { x.call(y).call(y) } }
16
+
17
+ # Traditional combinator name
18
+ W = Warbler # W combinator
19
+ W_direct = Warbler_direct
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smullyan
4
+ module Birds
5
+ # The Why bird (Y combinator) - fixed-point combinator
6
+ # Why f = f (Why f)
7
+ # Here's a practical implementation that works in applicative-order languages like Ruby
8
+ Why = ->(f) {
9
+ ->(x) { f.call(->(v) { x.call(x).call(v) }) }.call(
10
+ ->(x) { f.call(->(v) { x.call(x).call(v) }) }
11
+ )
12
+ }
13
+
14
+ # Alternative Z combinator (strict fixed-point) that's more suitable for eager evaluation
15
+ Z = ->(f) {
16
+ ->(x) { f.call(->(v) { x.call(x).call(v) }) }.call(
17
+ ->(x) { f.call(->(v) { x.call(x).call(v) }) }
18
+ )
19
+ }
20
+
21
+ # Traditional combinator names
22
+ Y = Why # Y combinator (fixed-point)
23
+ Sage = Why # Y combinator (alternative name)
24
+ end
25
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Smullyan
4
+ VERSION = "0.1.0"
5
+ end
data/lib/smullyan.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "smullyan/version"
4
+ require_relative "smullyan/birds/identity"
5
+ require_relative "smullyan/birds/kestrel"
6
+ require_relative "smullyan/birds/starling"
7
+ require_relative "smullyan/birds/bluebird"
8
+ require_relative "smullyan/birds/cardinal"
9
+ require_relative "smullyan/birds/warbler"
10
+ require_relative "smullyan/birds/mockingbird"
11
+ require_relative "smullyan/birds/why"
12
+ require_relative "smullyan/birds/lark"
13
+
14
+ module Smullyan
15
+ class Error < StandardError; end
16
+
17
+ # All combinators are now in separate files
18
+ module Birds
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smullyan
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Phil Crissman
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rake
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '13.0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '13.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: minitest
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.18'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '5.18'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rubocop
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.50'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.50'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rubocop-minitest
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '0.31'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '0.31'
68
+ description: A Ruby gem implementing the combinatory logic birds from Raymond Smullyan's
69
+ To Mock a Mockingbird
70
+ email:
71
+ - your-email@example.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - CLAUDE.md
77
+ - LICENSE
78
+ - README.md
79
+ - Rakefile
80
+ - lib/smullyan.rb
81
+ - lib/smullyan/birds/bluebird.rb
82
+ - lib/smullyan/birds/cardinal.rb
83
+ - lib/smullyan/birds/identity.rb
84
+ - lib/smullyan/birds/kestrel.rb
85
+ - lib/smullyan/birds/lark.rb
86
+ - lib/smullyan/birds/mockingbird.rb
87
+ - lib/smullyan/birds/starling.rb
88
+ - lib/smullyan/birds/warbler.rb
89
+ - lib/smullyan/birds/why.rb
90
+ - lib/smullyan/version.rb
91
+ homepage: https://github.com/philcrissman/smullyan
92
+ licenses:
93
+ - MIT
94
+ metadata:
95
+ allowed_push_host: https://rubygems.org
96
+ homepage_uri: https://github.com/philcrissman/smullyan
97
+ source_code_uri: https://github.com/philcrissman/smullyan
98
+ changelog_uri: https://github.com/philcrissman/smullyan/blob/main/CHANGELOG.md
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: 2.7.0
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubygems_version: 3.6.7
114
+ specification_version: 4
115
+ summary: A Ruby implementation of combinators from Raymond Smullyan's To Mock a Mockingbird
116
+ test_files: []