Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
型なし言語のための型
Search
Soutaro Matsumoto
November 03, 2019
Programming
14k
7
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
型なし言語のための型
富山Ruby会議01
Soutaro Matsumoto
November 03, 2019
More Decks by Soutaro Matsumoto
See All by Soutaro Matsumoto
Making the RBS Parser Faster
soutaro
0
890
API for docs
soutaro
4
3.5k
Rubyの標準添付ライブラリを開発する
soutaro
2
240
Embedding it into Ruby code
soutaro
4
27k
Parsing RBS
soutaro
0
2k
Ruby programming with types in action
soutaro
4
1k
IDE Development with Ruby
soutaro
4
1.2k
Ruby 3の新機能としての静的型検査の開発
soutaro
4
7.9k
An Introduction to Static Typing in Ruby 3
soutaro
3
490
Other Decks in Programming
See All in Programming
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
1.9k
AIチームを指揮するOSS「TAKT」活用術 / How to Use “TAKT,” an OSS Tool for Orchestrating AI Teams
nrslib
6
870
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
150
脅威をエンジニアリングの糧にして――現場編 / Turning Threats into Engineering Fuel — Field Edition
nrslib
0
270
Dataformのリポジトリを立ち上げるときにまずやること / dataform-day0-2026
snhryt
0
140
LLM Plugin for Node-REDの利用方法と開発について
404background
0
170
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
13
3.6k
Spec Driven Development | AI Summit Lisbon
danielsogl
PRO
0
170
並列実装の現場、2ヶ月間実務でAIを使い倒したAIもPCも私も限界が近い
ming_ayami
0
120
Signal Forms: Beyond the Basics @ngBaguette 2026 in Paris
manfredsteyer
PRO
0
230
Composerを使ったサプライチェーン攻撃の様子を眺めてみる #phpstudy
o0h
PRO
2
240
運用エージェントは "作る" から "育てる" へ - 記憶と自己進化の3層設計パターン / self-evolving-agents-three-layer-agent-design
gawa
12
3.6k
Featured
See All Featured
[RailsConf 2023] Rails as a piece of cake
palkan
59
6.7k
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
Un-Boring Meetings
codingconduct
0
310
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.4k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.1k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
360
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
130k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.5k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
38
2.9k
Designing for humans not robots
tammielis
254
26k
Site-Speed That Sticks
csswizardry
13
1.2k
Rails Girls Zürich Keynote
gr2m
96
14k
Transcript
ܕͳ͠ݴޠͷͨΊͷܕ দຊफଠ !TPVUBSP
@soutaro
@soutaro
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end ::Conference
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end ::Conference () { (::Talk) -> void } -> self
Ruby3ͷܕݕࠪ • RubyϓϩάϥϜͷࣜͷܕΛ࣮ߦͤͣʹఆ͠ɺ։ൃͷମݧΛվળ͢Δ • ύϑΥʔϚϯεతͰͳ͍ conf = Conference.find_by!(name: "ࢁRubyձٞ", volume:
1) conf.talks.each do |talk| puts talk.speaker.email end ::String ::Conference () { (::Talk) -> void } -> self
૬ؔਤ type-profiler Steep Sorbet RDL RBS (stdlib types) Level 1
ܕݕࠪ Level 2 ܕݕࠪ Type signature language
૬ؔਤ type-profiler Steep Sorbet RDL RBS (stdlib types) Level 1
ܕݕࠪ Level 2 ܕݕࠪ Type signature language ༻ ༻
૬ؔਤ type-profiler Steep Sorbet RDL RBS (stdlib types) Level 1
ܕݕࠪ Level 2 ܕݕࠪ Type signature language ༻ ༻ Ruby3ʹಉࠝ ͖ͳͷΛΠϯετʔϧ
3#4SVCZTJHOBUVSF w 3#4ΛಡΜͰɺΫϥεఆٛͷใΛॲཧ͢ΔϥΠϒϥϦ w ৄ͘͠དྷिͷ3VCZ)BDL$IBMMFOHF)PMJEBZͰ IUUQTSIDDPOOQBTTDPNFWFOU class Set[A] def initialize:
(_Each[A, untyped]) -> void | () -> void def intersection: (_Each[A, untyped]) -> self ... end
ΞτϥΠϯ w 3VCZͷ w ܕͳ͠ݴޠͷͨΊͷܕ w 5ZQF4DSJQUͱ࠷ۙͷྲྀΕ w 3VCZͷͨΊͷܕ
ܕͳ͠ݴޠͷͨΊͷܕ w ܕ w ίϯύΠϧ࣌ʹ໌͢Δࣜͷଐੑ w ͋ΔछͷޡΓΛݕग़Ͱ͖Δʢܕݕࠪʣ w ܕͳ͠ݴޠ w
ίϯύΠϧ࣌ʹܕݕࠪ͞Εͳ͍ݴޠʢ㲈ಈతܕ͚ݴޠʣ w 3VCZͱ͔
ίʔυฤू ίϯύΠϧ ࣮ߦ ܕݕࠪ ίʔυฤू ίϯύΠϧ ࣮ߦ ܕݕࠪ
class Person def name @name end def name=(value) @name =
value end end if rand(10) < 5 person = Person.new person.nme = "Soutaro Matsumoto" # NoMethodError end w ܕݕࠪʹΑͬͯɺཏతʹʢJGͷதʣݕࠪ͞Εͯɺ࣮ ߦલʹ͕ݕग़͞ΕΔʢίϯύΠϧ࣌ʣ w ܕݕࠪ͠ͳ͍߹ʹɺϓϩάϥϜͷ࣮ߦঢ়گʹΑͬ ͯɺ͕ݟ͔ͭΒͳ͍ʢ࣮ߦ࣌ʣ
ܕݕࠪͷಘࣦ w ͕ࣄલʹݕग़Ͱ͖Δ w ཏతͳݕࠪʢ࣮ߦͷύεʹґଘ͠ͳ͍ʣ w ॻ͚ΔϓϩάϥϜʹ੍ݶ͕ՃΘΔ w ࣮ࡍʹ࣮ߦ͞Εͳ͍ύεʹ͍ͭͯݕࠪ͞Εͯ͠·͏
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
ܕਪ 4PGU5ZQJOH (FOFSJDT '+ (SBEVBM5ZQJOH
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
ܕਪ 4PGU5ZQJOH (FOFSJDT '+ (SBEVBM5ZQJOH
4DIFNF 4.- )BTLFMM +BWB 3VCZ +BWB4DSJQU 1)1 1ZUIPO 5ZQF4DSJQU 4XJGU
ܕਪ 4PGU5ZQJOH (FOFSJDT '+ (SBEVBM5ZQJOH
.-ͷܕਪ w ʮ࠙ஸೡʹશ෦ͷࣜʹܕΛॻ͔ͳͯ͘ྑ͍ʯͱ͍͏ൃݟ w ύϥϝʔλଟ૬ʢେମ(FOFSJDTͷ͜ͱʣ # let rec map f
xs = match xs with [] -> [] | x::xs -> f x :: map f xs;; val map : ('a -> 'b) -> 'a list -> 'b list = <fun>
4PGU5ZQJOH w ܕͳ͠ͷݴޠʹܕΛ͚͍ͨ w ܕ͕͍ͭͨ෦Τϥʔ͕ݕग़Ͱ͖Δ w Θ͔Βͳ͍ͷ࣮ߦ࣌ʹݕࠪ͢Δ w ಈ͘ϓϩάϥϜͰ͖Δ͚ͩͦͷ··ܕݕࠪΛ௨͍ͨ͠ w
ܕऍઈରॻ͖ͨ͘ͳ͍
6OJPOUZQFT def f(x) if x 1 else "2" end end
6OJPOUZQFT def f(x) if x 1 else "2" end end
(bool) -> (Integer | String)
'MPXTFOTJUJWF5ZQJOH def g(n) n.abs # NoMethodError n.bytes # n: Integer
| String case n when Integer n.abs # n: Integer when String n.bytes # n: String end end (Integer | String) -> Integer
4PGU5ZQJOH w 4DIFNFϓϩάϥϜͷܕ͚ʹඞཁͳͷ͕Θ͔ͬͨ w 6OJPOUZQFT 'MPXTFOTJUJWFUZQJOH w ࣮ w
.-ͷܕਪʹجͮ͘ͷ w ϑϩʔղੳ͢Δͷ
ͬͱۙతͳݴޠͰʁ w +BWB4DSJQUͱ͔3VCZͱ͔< > w ΦϒδΣΫτʹର͢Δଟ૬ੑ BLBμοΫλΠϐϯά w ʮ͋Δϝιου͕ఆٛ͞Ε͍ͯΔҙͷΫϥεʯΈ͍ͨͳܕ
def add(x, y) x + y end def add: [A, B] ({ +: (A) -> B }, A) -> B
3VCZͰࢼͨ͠ͱ͜Ζ w ͬͺΓݫ͍͠ w .-ͷܕਪͰॲཧͰ͖ͳ͍ఆ͕ٛͰͯ͘Δ "SSBZNBQ w Ϋϥεఆ໋͕ٛྩతʹมΘ͍ͬͯ͘ͷ͕ݫ͍͠ʢϝλϓϩάϥϛϯάʣ w
ͦͦյΕ͍ͯΔఆ͕ٛͨ͘͞Μ͋Δ w "SSBZTFMFDUWT0CKFDUTFMFDU w )BTIΛฦ͢IBTIΛఆٛͨ͜͠ͱ͕ͳ͍ਓ
"SSBZJTB0CKFDU w 0CKFDUʹରͯ͠ಈ͘ϓϩάϥϜ"SSBZʹରͯ͠ಈ͘ʁʁ class Object def use_select select [STDIN], [],
[] end end "".use_select # OK [1,2,3].use_select # ????
4PGU5ZQJOH͔ΒಘΒΕͨݟ w จͰޭ͍ͯ͠ΔΑ͏ʹݟ͑Δ͕࣮༻Ϩϕϧͷͷͳ͍ w ඞཁͦ͏ͳܕγεςϜͷػೳΘ͔͖ͬͯͨ w Ή͠ΖܕΛॻ͍ͨํ͕ྑ͍ͷͰʁʁ w ϓϩάϥϚͷҙਤΛܕͰදݱ͢Δ w
ҙਤͱҰக͠ͳ͍ίʔυΛݕग़͢Δ
(SBEVBM5ZQJOH w ਐతܕ͚ w ܕͳ͠ͷίʔυͱܕ͖ͭͷίʔυΛࠞͥΔ w ͩΜͩΜܕΛ͚͍ͯ͘ w ܕॻ͘
ܕͳ͠ݴޠͷͨΊͷܕ w ͦΕͳΓʹڧྗͳܕγεςϜ w 6OJPOUZQFT qPXTFOTJUJWFUZQJOH HFOFSJDT w μοΫλΠϐϯά
w ߏత෦ܕ w ΫϥεͷܧঝؔΛ͋ͱͰมߋͰ͖ΔΈ )BTLFMM 4XJGU $ w (SBEVBM5ZQJOH
ΞτϥΠϯ w 3VCZͷ w ܕͳ͠ݴޠͷͨΊͷܕ w 5ZQF4DSJQUͱ࠷ۙͷྲྀΕ w 3VCZͷͨΊͷܕ
࠷ۙͷྲྀߦ w ܕ͖ͭͷํݴ w 5ZQF4DSJQU 5ZQFE4DIFNF w ܕऍͷαϙʔτ w 1ZUIPO
1)1
5ZQF4DSJQU w ݱࡏͰҰ൪উ͍ͬͯΔܕ͖ͭํݴ w λʔήοτݴޠ+4ʢϥϯλΠϜ+4ʣ class Drawer<ClothingType> { contents: ClothingType[]
= []; add(object: ClothingType) { this.contents.push(object); } } interface Sock { color: string } interface TShirt { size: "s" | "m" | "l" } const drawer: Drawer<Sock> = new Drawer() drawer.push({ color: "white" }) drawer.push({ size: "s" })
5ZQF4DSJQUͷ͍͢͝ͱ͜Ζ w ܕͳ͠ݴޠʹܕΛ͚Δਓྨͷເ͕ͬͨ w ΈΜͳܕΛॻ͍͍ͯΔͷ͕͍͢͝ w ߏతͳܕ͚ͩͰͳΜͱ͔ͳͬͯΔͷ͕͍͢͝ w 6OJPOUZQFTͱ͔qPXTFOTJUJWFUZQFTͱ͔MPHJDBMUZQFTͱ͔͠Εͬͱ ೖͬͯΔͷ͕͍͢͝
w ϥϯλΠϜͱͷ੍ΛΓӽ͑ͯಈ͍ͯΔͷ͕͍͢͝
ܕॻ͔ͳ͍͚ͯ͘ͳ͍ w ΑͬΆͲࣗ໌ͳͷҎ֎ॻ͘ w ϥΠϒϥϦͷܕEFpOJUFMZUZQFEʹू·͍ͬͯΔ const numbers: number[] = [1,2,3]
numbers.map<string>(x => x.toString())
jQuery.d.ts
ߏతͳܕ w ΫϥεͷܧঝؔͰͳ͘ɺϝιουͷू߹Ͱ෦ܕؔΛఆ͢Δ w ߏతͳܕ͚ͩͱ͍͏ͷ͍͠ w ͋Δ interface ForEach<A> {
forEach: (fun: (a: A) => void) => void } const x: ForEach<number> = [1,2,3]
ͨ·ͨ·ಉ͡ߏ͕͋ͬͨΒʁ w 5γϟπͱζϘϯ͕۠ผͰ͖ͳ͘ͳΔ w #SBOEFEUZQFͰରԠ͢Δ interface TShirt { size: "s"
| "m" | "l"; } interface Pants { size: "s" | "m" | "l"; }
ͨ·ͨ·ಉ͡ߏ͕͋ͬͨΒʁ w 5γϟπͱζϘϯ͕۠ผͰ͖ͳ͘ͳΔ w #SBOEFEUZQFͰରԠ͢Δ interface TShirt { size: "s"
| "m" | "l"; } interface Pants { size: "s" | "m" | "l"; } interface TShirt { type: "tshirt" size: "s" | "m" | "l"; } interface Pants { type: "pants" size: "s" | "m" | "l"; }
6OJPO5ZQFT'MPXTFOTJUJWF5ZQJOH w OVMMVOEFpOFEͱ͏·͘ΕΔΑ͏ʹͳͬͨ const x: string | undefined = ...
// Object is possibly 'undefined'. x.toUpperCase() if (x) { x.toUpperCase() }
ϥϯλΠϜͷ੍ w +4ͷϥϯλΠϜʹͰ͖ͳ͍͜ͱ54ͰͰ͖ͳ͍ w ʮ͋Δ͕ΠϯλʔϑΣʔεʹద߹͍ͯ͠Δ͔ݕ͍ࠪͨ͠ʯ w Ϣʔβʔ͕ࣗͷͰݕূ͢Δ -PHJDBMUZQFT •
function isPants(object: any): object is Pants { return object.type == "pants" }
ݟ w ਓؒܕΛॻ͘ w ʢܕΛॻ͖ͨ͘ͳ͍ਓ5ZQF4DSJQUΛΘͳ͍ͷͰ؍ଌͰ͖ͳ͍ʣ w େମ+BWB4DSJQUͷίʔυʹܕ͕ͭ͘ w 6OJPOUZQFTͱ͔qPXTFOTJUJWFUZQJOHͱ͔͕ॏཁ w
ߏత෦ܕಈ͘ w ϥϯλΠϜͷ੍ݶΛΓӽ͑ΔͨΊ JTܕ
1ZUIPO 1)1 w ϝιουͷܕΛॻ͘ه๏͕ಋೖ͞Εͨ w ܕݕ࣮ࠪߦ࣌ w ϝιουݺͼग़͠ͷͱ͖ʹܕݕࠪ͢Δ w ੩తͳܕݕࠪث։ൃ͞Ε͍ͯΔ
function sum(int $a, int $b) { return $a + $b; }
ΞτϥΠϯ w 3VCZͷ w ܕͳ͠ݴޠͷͨΊͷܕ w 5ZQF4DSJQUͱ࠷ۙͷྲྀΕ w 3VCZͷͨΊͷܕ
3VCZͷͨΊͷܕ w 4PGUUZQJOHͷݟˠਪΛؤுΔͷઓతʢ!NBNFʣ w 5ZQF4DSJQUͷݟ w ਓྨܕΛॻ͘ w ͦΕͳΓʹڧྗͳܕγεςϜ͕͋Ε্ख͘Εͦ͏ w
1ZUIPO 1)1ͷݟ w ܕऍܾΊͳ͍ͱ͍͚ͳ͍ w ܕݕࠪثผπʔϧʹ͢Δ
ܕऍͷه๏ 3#4 w গͳ͘ͱϥΠϒϥϦͷܕΛॻ͘ํ๏͕ඞཁ w ܕݕࠪπʔϧ͕ͦΕͧΕʹ༻ҙ͢Δͷ͔ͳΓݫ͍͠ w ϥϯλΠϜͷݕ͕ࠪͰ͖Δ͚ͩͰͦΕͳΓʹخ͍͠Ͱʁ w ιʔείʔυʹຒΊࠐΉߏจ࠾༻͠ͳ͍
ΈࠐΈͷܕऍߏจʢෆ࠾༻ʣ class Box extend T::Sig extend T::Generic Elem = type_member
sig {returns(Elem)} # @type var box: Box[Integer] box = Box.new box.x = "hello" &NCFEEFE%4- 4PSCFU $PNNFOUT 4UFFQ class Box [A] def value: A; ...; end def value=(value: A): A; ...; end end a: Box[Integer] = Box.new
ͦΕͳΓʹϦονͳܕ w λϓϧɺϨίʔυ [Integer, Symbol] w Ϧςϥϧܕ 1, "hello", :world
w 6OJPOUZQFT Integer | String w 0QUJPOBMUZQFTɺ(FOFSJDTʜ Array[String]? w յΕ͍ͯΔͷJODPNQBUJCMF incompatible def select: [A] () { (Elem) -> A
μοΫλΠϐϯά w JOUFSGBDFΛఆٛͯ͠ɺཁٻ͞ΕΔϝιουͷू߹Λॻ͘ w ϝιου͕͋Δ͔ͳ͍͔Ͱݕࠪ͞ΕΔ interface _Push def <<: (String)
-> void end def foo: (_Push) -> void def foo(a) a << "hello" end foo [] foo "" foo 3 # Τϥʔ
࣮ߦ࣌ݕ͚ࠪͩͰ w γάωνϟΛॻ͍ͨΒɺϢχοτςετͰςετ͢Δํ๏Λఏڙ w ϝιουݺͼग़͠ͷલޙʹܕݕࠪΛૠೖ w IUUQTSIDDPOOQBTTDPNFWFOU $ RBS_TEST_TARGET='Goodcheck::*' \
RBS_TEST_RAISE=true \ RUBYOPT='-rbundler/setup -rruby/signature/test/setup' \ RBS_TEST_OPT='-rset -rpathname -Isig' \ bundle exec rake test
IUUQTHJUIVCDPNTJEFSHPPEDIFDLUSFFSCT
·ͱΊ w 4PGUUZQJOHΈ͍ͨʹਪΛؤுΔͷ߹ཧతͰͳ͍ w ܕΛॻ͔ͳ͍ͷݫ͍͠ w ਓؒܕΛॻ͘ʢ͜͜ͰಘΒΕͨݟʣ w 3VCZͷͨΊͷܕ w
ΘΓͱϦονͳܕ(FOFSJDTɺ6OJPOUZQFTɺ'MPXTFOTJUJWFUZQJOH w μοΫλΠϐϯάؤுΔʢߏత෦ܕʣ
w <$BSUXSJHIU >3$BSUXSJHIUBOE.'BHBO4PGUUZQJOH w <.BUTVNPUP >4.BUTVNPUPBOE:.JOBNJEF5ZQF*OGFSFODFGPS3VCZ 1SPHSBNTCBTFEPO1PMZNPSQIJD3FDPSE5ZQFT w <+FOTFO >4)+FOTFOBOE".MMFSBOE15IJFNBOO
5ZQF"OBMZTJTGPS +BWB4DSJQU w <4JFL >+4JFLBOE85BIB (SBEVBM5ZQJOHGPS0CKFDUT w <)PDITUBEU >45)PDITUBEU 5ZQFE4DIFNF'SPN4DSJQUTUP1SPHSBNT w