ãµã³ãã«ããå¦ã¶TypeProviderã®ä½ããã
å
æ¥ã®ç¬¬5åFun Fan Fsharpã§åãããã¤ãã¼(TypeProvider)ã®è©±ãããã¾ããã
æè¿ã¯å
¨ç¶TypeProviderã触ã£ã¦ããªãã£ãã®ã§ãããä¹
ãã¶ãã«è§¦ã£ã¦ã¿ããã¼ãã¨æã£ã¦è²ã
触ã£ã¦ã¿ã¾ããã
çºè¡¨è³æã§ããã£ãããã«ãã¤ããã㯠dotnet
ã³ãã³ãã§ãã³ãã¬ã¼ããæä¾ããã¦ãããã§ãããã»ã»ã»
TypeProviderã¨ã¯
ã³ã³ãã¤ã«æã«å(Type)ãæä¾ãã(Provide)ããã¿ã§ãã åãããããã®ã¯JSONã¨ãCSVã¨ãã«å¯¾ãããã®ã§ããããã
#r "nuget: FSharp.Data" open FSharp.Data // JsonProviderã使ã£ã¦ã[{"name": "aaa", "age": 20}]ã¨ããå½¢ã«å¯¾å¿ããåãæä¾ãã¦ããã // <...>ã®ä¸ããéçãã©ã¡ã¼ã¿ã¼ãã§ãJsonProviderã¯ãã®æ å ±ã使ã£ã¦åãä½ããæä¾ãã type Users = JsonProvider<"""[{"name": "aaa", "age": 20}]"""> // ãã¼ã¿ããã¼ã¹(æ¬æ¥ãªãAPIå©ãã¦åã£ã¦ãããããªã¤ã¡ã¼ã¸) let users = Users.Parse(""" [ {"name": "Ken", "age": 25}, {"name": "Bob", "age": 30} ] """) for user in users do // NameãAgeã¨ãã£ã表è¨ã§ã¢ã¯ã»ã¹å¯è½ãå½ç¶ãã³ã¼ãè£å®ãå¹ãã let name = user.Name let age = user.Age printfn $"%s{name}:%d{age}"
ãããã¯TypeProvider以åã§ã¯ãã³ã¼ãçæãæååãã¼ã¹ã§ã®ã¢ã¯ã»ã¹ã§è§£æ±ºãã¦ããåé¡ã§ãã ããã¼ã¿ãåã£ã¦ãã¦ããããç³»ã®ã³ã¼ãã¯TypeProviderã«ãã£ã¦ã³ã¼ãè£å®ãå¹ãããã«ãªããé常ã«æ¸ãããããªãã¾ããã
TypeProviderãä½ã
ãããªä¾¿å©ãªTypeProviderã§ãããä½ãã¨ãªãã¨ãã¼ãã«ãé«ãã£ãããã¾ãã ã¡ãã£ã¨ã§ããã¼ãã«ãä¸ããããããªãã¨ããã®ããã®è¨äºã®ç®æ¨ã§ãã
æºå
çºè¡¨è³æãåèã«ã
dotnet new -i FSharp.TypeProviders.Templates
ãã¦ã
dotnet new typeprovider -o TP
ãã¦ãglobal.json
ã® version
ã dotnet --list-sdks
ãã¦åºã¦ãããã¼ã¸ã§ã³ã«æ¸ãæã(èªåã®ç°å¢ã§ã¯6.0.201)ã
paket.dependencies
ã® FSharp.Core
ã®ãã¼ã¸ã§ã³ã 6.0.3
ã«æ¸ãæãã
TP.Runtime.fsproj
ã® FSharp.Core
ã®ãã¼ã¸ã§ã³ã 6.0.3
ã«æ¸ãæãã
cd TP dotnet tool restore dotnet paket update dotnet build
ãããã®ã¨ãã¦é²ãã¾ãã
ä»ã«ããTP.Tests.fsproj
ã® TargetFramework
ã net6.0
ã«æ¸ãæãã¾ããã
ProvidedTypes.fs / ProvidedTypes.fsi
TypeProviderãä½ãããã«ã»ã¼å¿
é ãªã®ããããã®ãã¡ã¤ã«ã§ã*1ã
çºè¡¨è³æéãã«ããã°ãpaket-files/fsprojects/FSharp.TypeProviders.SDK/src
ã®ä¸ã«ãã¦ã³ãã¼ãããã¦ãã¾ãã
ãããã®ãã¡ã¤ã«ãé常ã«éè¦ãªã®ã§ãããProvidedTypes.fs
ã¯ãªãã¨16,000è¡ç¨åº¦ããè¶
巨大ãã¡ã¤ã«ã§ãã
ãããã«ãããå
¨é¨ç解ããã®ã¯é£ããã¨ããã®ããTypeProviderèªä½ã®ã²ã¨ã¤ã®ãã¼ãã«ã«ãªã£ã¦ããã®ã§ã¯ãªãããã¨æãã¾ãã
ProvidedTypes.fsi
ã¯560è¡ãªã®ã§ãå¿
è¦ã«ãªãAPIã¯éããããã®ã®ããã§ã大ããã§ãã
ããã§ä»åã¯ããã³ãã¬ã¼ãã«ãã£ã¦çæããããµã³ãã«ã解説ãããã¨ã§ã TypeProviderãä½ãå§ããããå¿ è¦æå°éã®ç解ãå¾ããããã¨ãç®æ¨ã«ãã¾ãã
ãã³ãã¬ã¼ãã§çæãããããã¸ã§ã¯ã
ãã³ãã¬ã¼ãã§çæãããããã¸ã§ã¯ãã¯ã3ã¤ããã¾ãã
ã¾ã㯠DesignTime
ããã¸ã§ã¯ãã§ãã
ãã®ããã¸ã§ã¯ãã«ã¯ãTypeProviderã®å®è£
ãå«ã¾ãããä¸çªéè¦ãªããã¸ã§ã¯ãã§ãã
ã¢ã»ã³ããªã«ã¯ TypeProviderAssembly
å±æ§ãå«ãããã«ãã¾ãã
ãã®ããã¸ã§ã¯ãã¯ãã³ã³ãã¤ã«æã«å¿
è¦ã¨ãªãå®è£
ãå«ãããã«ãã¾ã*2ã
次㫠Runtime
ããã¸ã§ã¯ãã§ãã
ãã®ããã¸ã§ã¯ãã«ã¯ãDesignTime
ã®dllãæå®ãã TypeProviderAssembly
å±æ§ãå«ãããã«ãã¾ãã
TypeProviderèªä½ã®å®è£
ã¯ã³ã³ãã¤ã«æã«åããã®ãªã®ã§ãå®è¡æã«ã¯ä¸è¦ã§ãã
ãã®ããããã®ããã« DesignTime
㨠Runtime
ã§åå²ãã¦ãTypeProviderã使ãå´ã§ã¯ Runtime
ã®ã¿ãåç
§ãããããªæ§æãåãã®ãããããã§ãã
fspoj
ãã¡ã¤ã«ãè¦ã¦ã¿ãã¨ãDesignTime
ããã¸ã§ã¯ãã®åç
§ã« IsFSharpDesignTimeProvider
ã¨ããè¨å®ãä»ãã¦ããããFSharpToolsDirectory
㨠PackagePath
ã« typeproviders
ãè¨å®ããã¦ãã¾ããããããã®å¹æã¯ããããã£ã¦ãã¾ããã
æå¾ã« Test
ããã¸ã§ã¯ãã§ãã
Runtime
ããã¸ã§ã¯ããåç
§ãã¦ãã¦ãå®éã«TypeProviderã使ããããªã³ã¼ãã«ãªã£ã¦ãã¾ãã
ãã³ãã¬ã¼ãã§çæããããµã³ãã«ã®TypeProvider
ãã³ãã¬ã¼ãã§çæãããã³ã¼ãã«ã¯ã2ã¤ã®TypeProviderã®å®è£
ããµã³ãã«ã¨ãã¦å«ã¾ãã¦ãã¾ãã
BasicErasingProvider
㨠BasicGeneraGenerativeProvider
ã§ãã
å ±éé¨å
両è ã§å ±éããé¨åãè¦ãã¨ãTypeProviderã£ã¦ãããªãã®ãªã®ããã¨ããé°å²æ°ãæ´ããããããã¾ããã
TypeProvider
å±æ§ãä»ãã¦ãã- ã³ã³ã¹ãã©ã¯ã¿ã¼ã§
TypeProviderConfig
ãåãåã£ã¦ãã TypeProviderForNamespaces
ãç¶æ¿ãã¦ããcreateType(s)
ã®ä¸ã§ProvidedTypeDefinition
ãä½ã£ã¦ãã- ä½ã£ããªãã¸ã§ã¯ãã«å¯¾ãã¦
AddMember
ãå¼ã³åºãã¦ãã - æçµçã«ã¯ãä½ã£ããªãã¸ã§ã¯ããè¿ãã¦ãã(ãªã¹ãã«å ããã©ãããã¨ããéãã¯ãã)
- ä½ã£ããªãã¸ã§ã¯ãã«å¯¾ãã¦
- ã³ã³ã¹ãã©ã¯ã¿ã¼ã®å¦ç(
do
ã®é¨å)ã§this.AddNamespace
ãå¼ã³åºãã¦ãã- 第äºå¼æ°ã«ã¯
ProvidedTypeDefinition
ãªãã¸ã§ã¯ãã®ãªã¹ãã渡ãã¦ãã
- 第äºå¼æ°ã«ã¯
大ä½ã¯ãããªã¨ããã§ãã TypeProviderã®éè¦ãªé¨åã¯ãä¸ã§å¤§ä½ã¾ã¨ã¾ã£ã¦ãã¾ãã
BasicErasingProvider
ã§ã¯ãBasicErasingProvider
ãã©ã®ããã«å®è£
ããã¦ããã®ãã«ã¤ãã¦è¦ã¦ã¿ã¾ãããã
[<TypeProvider>] type BasicErasingProvider (config : TypeProviderConfig) as this = inherit TypeProviderForNamespaces ( config, assemblyReplacementMap=[("TP.DesignTime", "TP.Runtime")], addDefaultProbingLocation=true) ...
ã¾ããåºåºã¯ã©ã¹ TypeProviderForNamespace
ã®ã³ã³ã¹ãã©ã¯ã¿ã¼ã«è²ã
ã¨æ¸¡ãã¦ãã¾ãã
config
ã¯ãã®ã¾ã¾æ¸¡ãã¦ããã®ã§ããã¨ãã¦ãassemblyReplecementMap
ã« DesignTime
ã®ã¢ã»ã³ããªå㨠Runtime
ã®ã¢ã»ã³ããªåã渡ãã¦ãã¾ãã
ããã¯ãDesignTime
㨠Runtime
ã«åå²ãã¦ãã¦ããã®ã§å¿
è¦ã«ãªãã¾ãã
Runtime
ãéã㦠DesignTime
ã®æ©è½ã使ãããã®è¨è¿°ã¨ããç解ã§ãã
ã§ãã®ã§ãã¢ã»ã³ããªãåå²ããªãå ´åã¯ä¸è¦ã§ãã
ã¾ããä»ã«ã addDefaultProbingLocation=true
ãæå®ãã¦ãã¾ãã
ããã true
ã«ããã¨ãã¢ã»ã³ããªã®æ¢ç´¢ãã£ã¬ã¯ããªã«å®è¡ä¸ã®ã¢ã»ã³ããª(Assembly.GetExecutingAssembly
ã§åããã¢ã»ã³ããª)ã®å ´æã追å ããã¾ãã
æå®ããªãå ´å㯠false
æ±ãã§ãããä»åã®ããã«åç¬ã§å®çµãããããªTypeProviderã®å ´å false
ã§ãåé¡ãªãã¯ãã§ã*3ã
... let myType = ProvidedTypeDefinition(asm, ns, "MyType", Some typeof<obj>) ...
ProvidedTypeDefinition
ãããã®TypeProviderã«ãã£ã¦æä¾ãããåã§ãã
ããã§ã¯ã¢ã»ã³ããªã¨åå空éã¨ååã¨ãã¼ã¹ã®åã渡ãã¦ä½ã£ã¦ãã¾ã*4ã
æ¶å»åã®ã¢ã»ã³ããªã«ã¯ Assembly.GetExecutingAssembly()
ãããã®ã渡ãã¦ãããå¿
è¦ãããããã§ãã
ããã¦ããã¼ã¹ã®åã« obj
ãæå®ãã¦ãã¾ãã
ãã®ããã¼ã¹ã®åãã¨ããã®ã¯é常ã«éè¦ãªãã®ãªã®ã§ããããµã³ãã«ã説æã§ã¯ãã obj
ã使ããã¦ãã¦åå¨æ義ãããåãããªããã®ã«ãªã£ã¦ãã¾ã£ã¦ãã¾ãã
æ¶å»åã«ããã¦ã¯ããã¼ã¹ã®åã¯ã³ã³ãã¤ã«å¾ã«ç¾ããåã«ãªãã¾ã*5ã
ä¾ãã°ãåé ã§ç´¹ä»ãã JsonProvider
ã¯æ¶å»åã§ããµã³ãã«ã§ã®ãã¼ã¹ã®å㯠IJsonDocument[]
ã§ãã
ãã®ãããusers
ã¯é
åã¨ãã¦æ±ãã¾ã(ãªã®ã§ãforã§åãã¦ããã®ã§ã)ã
ãµã³ãã«ãæ¹å¤ãã¦ãJsonProvider
ã«ä¸ããJSONãå¤ãã¦ã¿ã¾ãããã
#r "nuget: FSharp.Data" open FSharp.Data type User = JsonProvider<"""{"name": "aaa", "age": 20}"""> let user = User.Parse(""" {"name": "Ken", "age": 25} """) // å½ç¶ãä»ã¾ã§ã®ããã«ããããã£ã¼ã§ã®ã¢ã¯ã»ã¹ãã§ãããã»ã»ã» let name = user.Name let age = user.Age printfn $"%s{name}:%d{age}" // JsonDocumentã¨ãã¦ã使ãã match user.JsonValue with | JsonValue.Record xs -> printfn $"%A{xs}" | _ -> printfn ""
ãã®å ´åããã¼ã¹ã®å㯠JsonDocument
ã¨ãªãã¾ãã
æ¶å»åã§ã¯ãä¸ã®ä¾ã§ user.Name
ã®ãããªã¢ã¯ã»ã¹ã¯ãã¼ã¹åã§ã®æä½ã«è£ã§å¤æããããããªå®è£
ã«ãªã£ã¦ãããã¨ãå¤ãã§ãã
ã¾ããJsonProvider
ã®ä¾ã®ããã«ããã¼ã¹ã®åã¯TypeProviderã«æ¸¡ãããæ
å ±ã«ãã£ã¦å¤ããå ´åãå¤ãè¦ããã¾ãã
ãã®ã»ãã以ä¸ã®ãããªè¿½å ã®ãªãã·ã§ã³å¼æ°ãæå®ã§ãã¾ãã
å¼æ°å | å | ããã©ã«ãå¤ | æå³ |
---|---|---|---|
hideObjectMethods | bool | false | objã®ã¡ã½ãããé ããã©ãã |
nonNullable | bool | false | nullãå¼¾ããã©ãã*6 |
isErased | bool | true | æ¶å»åãã©ãã |
isSealed | bool | true | sealedã«ããã |
isInterface | bool | false | interfaceã«ããã |
isAbstract | bool | false | abstractã«ããã |
ã¡ãªã¿ã«ãhideObjectMethods
㯠TypeProviderEditorHideMethods
ãªãå±æ§ã«ãã£ã¦å®ç¾ããã¦ããããã§ãã
... let ctor = ProvidedConstructor( [], invokeCode = fun args -> <@@ "My internal state" :> obj @@> ) myType.AddMember(ctor) let ctor2 = ProvidedConstructor( [ProvidedParameter("InnerState", typeof<string>)], invokeCode = fun args -> <@@ (%%(args.[0]):string) :> obj @@> ) myType.AddMember(ctor2) ...
ProvidedConstructor
ãªãã¸ã§ã¯ããä½ã£ã¦ãmyType
ã« AddMember
ãã¦ãã¾ãã
myType
ã¯ãå
ã»ã©ä½ã£ã ProvidedTypeDefinition
ãªãã¸ã§ã¯ãã§ãã
ProvidedConstructor
ã®ã³ã³ã¹ãã©ã¯ã¿ã¼ã¯ ProvidedParameter list
㨠Expr list -> Expr
ãåãåãã¾ãã
ctor2
ãF#ã®ã³ã¼ãã§æ¸ãã¨ãããªãããããªæãã§ãã
new (InnerState: string) = InnerState :> obj
ãã®ããã«ãTypeProviderãä½ãã«ã¯ã³ã¼ãå¼ç¨ç¬¦ã«ããããã°ã©ãã³ã°ã«ããç¨åº¦æ £ãã¦ããå¿ è¦ãããã¾ãã ã¾ããæ¶å»åã§ã¯ã³ã³ã¹ãã©ã¯ã¿ã¼ã§è¿ãå¤ã¯ãã¼ã¹ã®åãä¸è´ããã¦ããã¾ããã*7ã
... let innerState = ProvidedProperty( "InnerState", typeof<string>, getterCode = fun args -> <@@ (%%(args.[0]) :> obj) :?> string @@> ) myType.AddMember(innerState) ...
ã³ã³ã¹ãã©ã¯ã¿ã¼ã®æã¨åãããã«ãProvidedProperty
ãªãã¸ã§ã¯ããä½ã£ã¦ãmyType
ã« AddMember
ãã¦ãã¾ãã
ããããã£ã¼åãããããã£ã¼ã®åãã²ãã¿ã¼ã®å¦çã渡ãã¦ãã¾ãã
ä»ã«ããã»ãã¿ã¼ã®å¦çã static
ãã©ãããã¤ã³ãã¯ãµãã©ã¡ã¼ã¿ã¼ã渡ãã¾ãã
ãã®ããããã£ã¼ã¯é static
ãªã®ã§ãgetterCode
ã®æåã®å¼æ°ã« this
ã渡ããã¾ãã
æ¶å»åã«ããã this
ã¯ãã³ã³ã¹ãã©ã¯ã¿ã¼ã§è¿ããå¤ã«ãªãã¾ãã
ããããã£ã¼ã«éãããé static
ãªã¡ã³ãã¼ã¯æåã®å¼æ°ã« this
ãå
¥ã£ã¦ãã¾ãã
éã«ãstatic
ãªã¡ã³ãã¼ã¯ this
ã«ç¸å½ããå¤ã¯å
¥ã£ã¦ãã¾ããã®ã§ãå¼æ°ã®ã¤ã³ããã¯ã¹ã®ç®¡çã«ã¯æ³¨æãå¿
è¦ã§ãã
ä»ã«ã ProvidedMethod
ã ProvidedParameter
ã使ã£ã¦ã¡ã³ãã¼ã追å ãã¦ãã¾ããããã¨ã¯ä¼¼ããããªæãã§èªã¿ä¸ããã¯ãã§ãã
... do this.AddNamespace(ns, createTypes()) ...
æå¾ã«ãä½ã£ã ProvidedTypeDefinition
ã AddNamespace
ãã¦ãã¾ãã
ããã§æ¸¡ãåå空éåã¯ä½ã£ããªãã¸ã§ã¯ããæã£ã¦ãããã ãã渡ããªãã¦ããããããã»ã»ã»ã¨æããã§ããã渡ãããã«ãªã£ã¦ãã¾ãã
ã¡ãã£ã¨é¢åãªã®ã§ã誰ãåå空éåãæå®ããªãã¦ããããªã¼ãã¼ãã¼ãã追å ããpull requestæããã¨ããããããªãã§ããããã
BasicGenerativeProvider
BasicGenerativeProvider
ã¯éãé¨åãä¸å¿ã«è¦ã¦ã¿ã¾ãããã
å
é ããè¦ãã¨ãããã«ããã®ã§ãã¾ãã¯æ±ºå®çã«éãé¨åã§ãããéçãã©ã¡ã¼ã¿ã¼ã¾ããããè¦ã¦ã¿ã¾ãã
使ãå´ã確èªãã¦ããã¾ãã
// GenerativeProviderã«éçãã©ã¡ã¼ã¿ã¼2ã渡ãã¦ãã type Generative2 = TP.GenerativeProvider<2>
ãµã³ãã«ã§ã¯çæåã®ã¿éçãã©ã¡ã¼ã¿ã¼ã使ã£ã¦ãã¾ãããéçãã©ã¡ã¼ã¿ã¼ã¯æ¶å»åã§ã使ããç¹ã«ã¯æ³¨æãå¿ è¦ã§ãã éçãã©ã¡ã¼ã¿ã¼ã«é¢ããè¨è¿°ã¯ãã®ãããã§ãã
... let myParamType = let t = ProvidedTypeDefinition(asm, ns, "GenerativeProvider", Some typeof<obj>, isErased=false) t.DefineStaticParameters( [ProvidedStaticParameter("Count", typeof<int>)], fun typeName args -> createType typeName (unbox<int> args.[0])) t do this.AddNamespace(ns, [myParamType]) ...
ã¾ããGenerativeProvider
ã¨ããååã® ProvidedTypeDefinition
ã asm
ãæå®ãã¦ä½ã£ã¦ãã¾ãã
éçãã©ã¡ã¼ã¿ã¼ãæã¤TypeProviderã¯TypeProviderèªä½ã表ã ProvidedTypeDefinition
ã¨ããã®TypeProviderãè¿ãåã表ã ProvidedTypeDefinition
ãå¿
è¦ã§ãã
ä¸ã® ProvidedTypeDefinition
ã¯åè
ã®ãTypeProviderèªä½ã表ã ProvidedTypeDefinition
ãã§ãã
ããã¦ãDefineStaticParameters
ã¡ã½ããã«ããéçãã©ã¡ã¼ã¿ã¼ãå®ç¾©ãã¦ãã¾ãã
å¼æ°ã¯éçãã©ã¡ã¼ã¿ã¼ã®å¼æ°ã®æ
å ±(ååã¨å((第ä¸å¼æ°ã¨ãã¦ããã©ã«ãå¤ãè¨å®å¯è½ã§ãã)))ã®ãªã¹ãã¨ããã®TypeProviderãè¿ãåãä½ãããã®é¢æ°ã§ãã
é¢æ°ã®å¼æ°ã« typeName
ã渡ããã¦ãã¾ãã®ã§ãããã使ã£ã¦ãã®TypeProviderãè¿ãåã表ã ProvidedTypeDefinition
ãä½ãã¾ã*8ã
次ã«ãTypeProviderãè¿ãåã表ã ProvidedTypeDefinition
ãä½ã£ã¦è¿ã createType
é¢æ°ã®ä¸èº«ãè¦ã¦ã¿ã¾ãã
... let asm = ProvidedAssembly() let myType = ProvidedTypeDefinition(asm, ns, typeName, Some typeof<obj>, isErased=false) ...
ã¢ã»ã³ããªã« ProvidedAssembly
ãçæãã¦æ¸¡ãã¦ãã¾ãã
çæå(isErased
ã false
)ã®TypeProviderãæä¾ããåã¯ããã®ããã« ProvidedAssembly
ã渡ãå¿
è¦ãããã¾ãã
... asm.AddTypes [ myType ] ...
createType
ã®æå¾ãã¸ãã«ä¸ã®ã³ã¼ããããã¾ãã
ãã®ããã«ãçæåã§ã¯ ProvidedAssembly
ã«ä½ã£ã ProvidedTypeDefinition
ã AddTypes
ãã¦ãããå¿
è¦ãããã¾ãã
ãã® AddTypes
ã ProvidedAssembly
ã«å®è£
ããã¦ãããããçæåã®TypeProviderãæä¾ããå㯠ProvidedAssembly
ã使ãå¿
è¦ãããã®ã§ãã
ãã®ä¾ã§ã¯éçãã©ã¡ã¼ã¿ã¼ã§æå®ããæ°å¤ã使ã£ã¦ããã®åæ°åã®ããããã£ã¼ãçããã¦ãã¾ãã æ¶å»åã§ãåãããã«ã§ãã¾ãã®ã§ãçæåã®ä¾ãåèã«ãã¦æ¸ãã¦ã¿ãã¨ç解ãé²ãããããã¾ããã
ãµã³ãã«ã§ä½¿ã£ã¦ããªãæ©è½
ãµã³ãã«ã§ä½¿ã£ã¦ããªãæ©è½ã ProvidedTypes.fs
ã«ã¯å¤ãå«ã¾ãã¦ãã¾ãã
ããããã¯ããã®ãªããã2ã¤ãé¸ãã§ç´¹ä»ãã¾ãã
implicit constructor
ã¾ãã¯ãProvidedConstructor
ã«ãã IsImplicitConstructor
ããããã£ã¼ã§ãã
ããã true
ã«ãããã¨ã§ããã©ã¤ããªã³ã³ã¹ãã©ã¯ã¿ã¼*9ã¨åããããªã³ã¼ããçæããã¾ãã
å®éã«ãã£ã¼ã«ããçæããå¿
è¦ããããããçæåã®ã¿ã§ä½¿ãã¾ãã
ä¾ãã°ã
let ctor = ProvidedConstructor( [ProvidedParameter("x", typeof<int>)], invokeCode = fun args -> <@@ null @@>) ctor.IsImplicitConstructor <- true
ã¨ãããã¨ã§ã
let p = ProvidedProperty( "X", typeof<int>, getterCode = fun args -> Expr.GlobalVar("x"))
ã®ããã«ãExpr.GlobalVar
ã§ã¢ã¯ã»ã¹ã§ããããã«ãªãã®ã§å°å³ã«ä¾¿å©ã§ãã
IsImplicitConstructor
ã« true
ãè¨å®ããªãå ´åã¯ã以ä¸ã®ããã«èªåã§è«¸ã
å®è£
ããå¿
è¦ãããã¾ãã
// ãã£ã¼ã«ããç¨æ let field = ProvidedConstructor("state", typeof<int>) myType.AddMember(field) // ã³ã³ã¹ãã©ã¯ã¿ã¼ã容æ let ctor = ProvidedConstructor( [ProvidedParameter("x", typeof<int>)], // ç¨æãããã£ã¼ã«ãã«è¨å®ããã³ã¼ããExprã¨ãã¦æ¸ã invokeCode = fun args -> Expr.FieldSet(args[0], field, args[1])) myType.AddMember(ctor) // ã¢ã¯ã»ã¹ã¯GlobalVarã§ã¯ãªããFieldGetã使ã let p = ProvidedProperty( "X", typeof<int>, getterCode = fun args -> Expr.FieldGet(args[0], field)) myType.AddMember(p)
ProvidedMethodã®DefineStaticParameters
F#4.0ã§å
¥ã£ãæ¡å¼µã«ãã¡ã½ããã«ãéçãã©ã¡ã¼ã¿ã¼ãæã¦ãããã«ãªã£ããã¨ãããã®ãããã¾ãã
éçãã©ã¡ã¼ã¿ã¼ãæã¤TypeProvider㯠type T = ...
ã®ãããªå½¢ã§åãåãã¦ããå¿
è¦ãããã
ã¡ã½ãããè¿ãåãéçãã©ã¡ã¼ã¿ã¼ã«ãã£ã¦æ±ºãããå ´åã«ã¯é¢åã§ããã
ProvidedMethod
ã® DefineStaticParameters
ã使ããã¨ã§ããã¡ãã¡åãåããå¿
è¦ããªããªãã¾ãã
let res = TP.Regex.TypedMatch<"(?<First>.)(?<Rest>.*)">("hoge") Assert.AreEqual("h", res.First) Assert.AreEqual("oge", res.Rest)
ãããªæãã«ãTypedMatch
ã¡ã½ããã®éçãã©ã¡ã¼ã¿ã¼ã«ãã¿ã¼ã³ãæå®ãã¦ã
è¿ã£ã¦ãããªãã¸ã§ã¯ãã«å¯¾ãã¦ã°ã«ã¼ãåã使ã£ã¦çµæã«ã¢ã¯ã»ã¹ãã¦ãã¾ãã
ãããã«å¤±æããå ´åã®èæ
®ãªã©ãã¦ãããä¸å®å
¨ãªå®è£
ã§ããããããªãã¨ãã§ããããã¨ããä¾ã¨ãã¦èãã¦ããã ããã°ã
[<TypeProvider>] type RegexTypeProvider (config: TypeProviderConfig) as this = inherit TypeProviderForNamespaces(config, assemblyReplacementMap=[("TP.DesignTime", "TP.Runtime")]) let ns = "TP" let asm = Assembly.GetExecutingAssembly() let providedType = ProvidedTypeDefinition(asm, ns, "Regex", Some typeof<obj>, hideObjectMethods=true) // æ»ãå¤ã®åãä½ã let createRetType typeName props = // asm, nsãæå®ããã«ProvidedTypeDefinitionãä½ã let t = ProvidedTypeDefinition(typeName, Some typeof<Match>, hideObjectMethods=true) let ctor = ProvidedConstructor([ProvidedParameter("res", typeof<Match>)], fun args -> args[0]) t.AddMember(ctor) // éçãã©ã¡ã¼ã¿ã¼ã®æ å ±ã使ã£ã¦ããããã£ãçãã for prop in props do let p = ProvidedProperty(prop, typeof<string>, getterCode = fun args -> <@@ let r = (%%(args[0]) : Match) r.Groups[prop].Value @@>) t.AddMember(p) // thisã«AddNamespaceããã®ã§ã¯ãªããprovidedTypeã«AddMemberãã(ãã¹ãããã¯ã©ã¹ã¨ãã¦å®ç¾©) providedType.AddMember(t) t // ã¡ã½ããã®å®ä½ãä½ã let createMethod methodName pattern = let props = Regex(pattern).GetGroupNames() |> Array.toList let retType = createRetType ("RetType" + methodName) props let meth = ProvidedMethod( methodName, [ProvidedParameter("str", typeof<string>)], // æ»ãå¤ã®åãä½ã£ãåã«ãã retType, isStatic = true, invokeCode = fun args -> <@@ Regex.Match(%%(args[0]), pattern) @@>) providedType.AddMember(meth) meth do // éçãã©ã¡ã¼ã¿ã¼ãåãã¡ã½ããã®å®ç¾© let meth = ProvidedMethod("TypedMatch", [], typeof<unit>, isStatic=true) meth.DefineStaticParameters( [ProvidedStaticParameter("Pattern", typeof<string>)], // ProvidedMethodãè¿ãããã«ãã fun methodName args -> createMethod methodName (args[0] :?> string) ) providedType.AddMember(meth) this.AddNamespace(ns, [providedType])
試ãã¦ãã¾ããããProvidedTypeDefinition
ã«ãéçãã©ã¡ã¼ã¿ã¼ãå®ç¾©ãã¦ã両æ¹ã®éçãã©ã¡ã¼ã¿ã¼ã使ãã
ã¨ãããã¨ãã§ããã¨æãã¾ãã
ProvidedTypeDefinition
å´ã«æ¥ç¶æååããProvidedMethod
å´ã«SQLãç½®ãã¦ããæãã«åãçæãããããªãã®ãã§ããããããã¾ããã
ã¾ã¨ã
TypeProviderãã¨ããããä½ãå§ããããããã«ãªãããã®æ å ±ã¯ä¸éã説æã§ããã¨æãã¾ãã ããã§ããã¨ã¯ä»ã¾ã§èªåçæã§è§£æ±ºãã¦ãããã®ã¨ããæååãã¼ã¹ã®ã¢ã¯ã»ã¹ããã¦ãããã®ã¨ããTypeProviderã«ç½®ãæããã ãã§ããï¼
*1:ãã«ããã®æ代ã«ã¯ITypeProviderãç´æ¥å®è£ ãã¦TypeProviderãä½ã£ãã®ã§ãããä»ãããã«ãããã人ã¯ã»ã¼ããªãã¨æãã¾ããããããTypeProviderãä½ã人ãå°ãªãã§ããã»ã»ã»
*2:ãµã³ãã«ã®fsprojã§ã¯ãRuntimeå´ã®ãã¡ã¤ã«ãå«ããããªæ§æã«ãªã£ã¦ãã¾ãããã®ããã«ãå®è¡æã«å¿ è¦ãªãã®ã¯Runtimeå´ã«ç½®ããã³ã³ãã¤ã«æã«ãå¿ è¦ã«ãªããã®ã¯DesignTimeå´ã«ãå«ãããããªæ§æã«ãã¾ãã
*3:ãªãã§ãã®ãµã³ãã«ãtrueã«ãã¦ããã®ãã¯è¬
*4:ã¢ã»ã³ããªã¨åå空éãæå®ããªãã³ã³ã¹ãã©ã¯ã¿ã¼ãããã¾ããããã¡ãã¯ãã¹ãããåãä½ãéã®ãã®ãªã®ã§ããããã¬ãã«ã®åã®æä¾ã«ã¯ä½¿ãã¾ããã
*5:çæåã§ã¯åºåºã¯ã©ã¹ã«ãªãã¾ãã
*6:ããã®ããã©ã«ããfalseãªã®ã¯ãF#3.0æ代ã¯ããããµãã¼ãããã¦ããªãã£ãããã ã¨æããã¾ãããã®æ©è½ã¯F#4.0ããå ¥ãã¾ããã
*7:å ´åã«ãã£ã¦ã¯ä¸è´ãããªãã¦ãåé¡ãªããã¨ããããã§ãããä¸è´ããã¦ããã®ãç¡é£ã§ãã
*8:ããã§éãååã使ãã¨ã¨ã©ã¼ã«ãªãã¾ãã
*9:ããããImplicit Constructorã£ã¦ç¨èªã ã£ãã®ã»ã»ã»ï¼
ã³ã³ãã¥ãã¼ã·ã§ã³å¼ã§ãã¼ã¯ã¼ãå¼æ° ãã®2
ã³ã³ãã¥ãã¼ã·ã§ã³å¼ã§ãã¼ã¯ã¼ãå¼æ°ãæ¹è¯ãã¾ããã ååã®è¨äºã§ã¯ã以ä¸ã®ãããªæ¬ ç¹ãããã¾ããã
- å®è¡å¹çãæªã
- ã¨ã©ã¼ã¡ãã»ã¼ã¸ãåããã«ãã
ä»åã¯ãã®2ã¤ã®æ¬ ç¹ã解決ãã¦ã¿ã¾ãããã
å®è¡å¹çããããã
ãã«ãã¼ã®ã¡ã½ããã« inline
æå®ãããã°ããæãã«ãªãã¾ãã
ãã®ãããªã³ã¼ããèãã¦ã¿ã¾ãã
let f () = "hoge hoge" |> substring { start 5; end_ 7 }
ãã®ã³ã¼ãã inline
ãä»ããã«ã³ã³ãã¤ã«ããILã¯ãã®ããã«ãªãã¾ãã
IL_0000: call class Program/SubstringBuilder Program::get_substring() IL_0005: ldc.i4.5 IL_0006: ldc.i4.7 IL_0007: call class Program/NotSet Program/NotSet::get_NotSet() IL_000c: newobj instance void class System.Tuple`3<int32,int32,class Program/NotSet>::.ctor(!0, !1, !2) IL_0011: callvirt instance class Microsoft.FSharp.Core.FSharpFunc`2<string,string> Program/SubstringBuilder::Run(class System.Tuple`3<int32,int32,class Program/NotSet>) IL_0016: ldstr "hoge hoge" IL_001b: tail. IL_001d: callvirt instance !1 class Microsoft.FSharp.Core.FSharpFunc`2<string,string>::Invoke(!0) IL_0022: ret
F#ã³ã¼ãã«ããã¨ãããªæãã§ããããã
let f () = "hoge hoge" |> substring.Run((5, 7, NotSet))
ã¿ãã«ãæ§ç¯ããããRun
ã§è¿ã£ã¦ããé¢æ°ãå¼ã³åºãã¦ãããã¨ããããã¾ãã
ããã«å¯¾ãã¦ãinline
ãä»ãã¦ã³ã³ãã¤ã«ããã¨ãã®ããã«ãªãã¾ãã
IL_0000: ldstr "hoge hoge" IL_0005: ldc.i4.5 IL_0006: ldc.i4.2 IL_0007: callvirt instance string System.String::Substring(int32, int32) IL_000c: ret
ãããF#ã³ã¼ãã«ããã¨ãããªæãã§ãã
let f () = "hoge hoge".Substring(5, 2)
ãã¹ã¦å±éãããåãªã Substring
å¼ã³åºãã«ã§ãã¦ãã¾ã*1ã
ã¨ã©ã¼ã¡ãã»ã¼ã¸ããããããããã
ãã®ãããªã³ã¼ããèãã¦ã¿ã¾ãã
let f () = "hoge hoge" |> substring { start 5; end_ 7; length 2 }
ããã§ãend_ 7
ã®é¨åãã¨ã©ã¼ã«ãªããã¨ã©ã¼ã¡ãã»ã¼ã¸ã¯ãã®ããã«ãªãã¾ãã
error FS0193: åã®å¶ç´ãä¸è´ãã¾ããã次ã®å 'int * int * NotSet' ã¯æ¬¡ã®åã¨äºææ§ãããã¾ãã 'int * NotSet * NotSet'
ããã¯ãå ã®ã³ã¼ããæå³çã«ã¯æ¬¡ã®ã³ã¼ãã¨åãã«ãªãããã§ãã
let b = substring "hogehoge" |> b.Run(b.Length(b.End(b.Start(b.Yield(()), 5), 7), 2))
End
ã®æ»ãå¤ã®å㯠'a * int * NotSet
ã§ãããLength
ã®å¼æ°ã®å㯠'a * NotSet * NotSet
ãªã®ã§ã
ãã®ãããªã¨ã©ã¼ã¡ãã»ã¼ã¸ã«ãªãã®ã§ã*2ã
ä¸å¯§ã«èªã¿è§£ãã°ããããªãã¯ãªãã¡ãã»ã¼ã¸ã§ãããããããããã¨ã¯è¨ãã¾ããã
ããã解決ããä¸ã¤ã®æ¹æ³ã¨ãã¦ã¯ãNotSet
ã®é¨åã«ã¡ãã»ã¼ã¸ãåãè¾¼ãæ¹æ³ãèãããã¾ãããã¡ãã£ã¨ç¡çç¢çæãé«ãã§ãã
F#6.0ããã«ã¹ã¿ã ãªãã¬ã¼ã¿ã¼ã®ã¡ã½ããããªã¼ãã¼ãã¼ãã§ããããã«ãªã£ãã®ã§ã
ãã㨠CompilerMessage
å±æ§ãçµã¿åãããã¨ããæãã«ã³ã³ãã¤ã«ã¨ã©ã¼ã¡ãã»ã¼ã¸ãä½ãã¾ãã
[<CustomOperation("length")>] [<CompilerMessage("lengthã¯end_ã¨ä¸ç·ã«ã¯ä½¿ãã¾ãã", 10001, IsError=true)>] member _.Length ((_: 'a, _: int, _: NotSet), _: int) : 'a * int * NotSet = failwith "oops!"
Length
ã¡ã½ããå´ã«ãªã¼ãã¼ãã¼ãã追å ããend_
ãè¨å®ããã¦ããã
ã¤ã¾ãã¯ç¬¬ä¸å¼æ°ã®ã¿ãã«ã®ç¬¬2è¦ç´ ã int
ã«ãªã£ã¦ãããªã¼ãã¼ãã¼ããé¸æãããå ´åã«ã
ã³ã³ãã¤ã«ã¨ã©ã¼ã«ãã¦ãã¾ãã®ã§ãã
ãã®ãããlength 2
ã®é¨åãã¨ã©ã¼ã«ãªããã¨ã©ã¼ã¡ãã»ã¼ã¸ã¯ãã®ããã«ãªãã¾ãã
error FS10001: lengthã¯end_ã¨ä¸ç·ã«ã¯ä½¿ãã¾ãã
以åã¯åè´ããã¡ã½ãããè¦ã¤ãããªãã£ããããEnd
å´ãã¨ã©ã¼ã«ãªã£ã¦ãã¾ãããã
ä»åã¯åè´ãããªã¼ãã¼ãã¼ããè¦ã¤ãã£ãããã§ã³ã³ãã¤ã«ã¨ã©ã¼ã«ãªãããã
ã¨ã©ã¼ã®å ´æãããèªç¶ãªå ´æã«åºãããã«ãªã£ã¦ãã¾ãã
ã¾ããæ»ãå¤ã®åãæå®ãã¦ãã¾ãã
æ»ãå¤ã®æ¹ãæå®ããªãå ´åã¯æ»ãå¤ã®åãã¸ã§ããªãã¯ã«ãªãã¾ãã
Run
ã¯ãªã¼ãã¼ãã¼ãããã¦ãããæ»ãå¤ã®åãã¸ã§ããªãã¯ã ã¨é©å㪠Run
ãé¸ã¹ã¾ããã
ãã®ãããsubstring
ã®é¨åã«ãã³ã³ãã¤ã«ã¨ã©ã¼ãåºã¦ãã¾ãã¾ãã
æ»ãå¤ã®åæå®ã¯ããããé¿ããããã«ä»ãã¦ãã¾ã*3ã
å ¨ä½
ä»åã®ã³ã¼ãã®å ¨ä½ã¯ãã®ããã«ãªãã¾ãã
type NotSet = NotSet type SubstringBuilder () = member inline _.Yield (()) = (NotSet, NotSet, NotSet) [<CustomOperation("start")>] member inline _.Start ((_: NotSet, endParam: 'b, lengthParam: 'c), start: int) = (start, endParam, lengthParam) [<CustomOperation("start")>] [<CompilerMessage("startã¯2åæå®ã§ãã¾ãã", 10001, IsError=true)>] member _.Start ((_: int, _: 'b, _: 'c), _: int) : int * 'b * 'c = failwith "oops!" [<CustomOperation("end_")>] member inline _.End ((startParam: 'a, _: NotSet, lengthParam: NotSet), end_: int) = (startParam, end_, lengthParam) [<CustomOperation("end_")>] [<CompilerMessage("end_ã¯2åæå®ã§ãã¾ãã", 10001, IsError=true)>] member _.End ((_: 'a, _: int, _: 'b), _: int) : 'a * int * 'b = failwith "oops!" [<CustomOperation("end_")>] [<CompilerMessage("end_ã¯lengthã¨ä¸ç·ã«ã¯ä½¿ãã¾ãã", 10001, IsError=true)>] member _.End ((_: 'a, _: NotSet, _: int), _: int) : 'a * NotSet * int = failwith "oops!" [<CustomOperation("length")>] member inline _.Length ((startParam: 'a, endParam: NotSet, _: NotSet), length: int) = (startParam, endParam, length) [<CustomOperation("length")>] [<CompilerMessage("lengthã¯2åæå®ã§ãã¾ãã", 10001, IsError=true)>] member _.Length ((_: 'a, _: 'b, _: int), _: int) : 'a * 'b * int = failwith "oops!" [<CustomOperation("length")>] [<CompilerMessage("lengthã¯end_ã¨ä¸ç·ã«ã¯ä½¿ãã¾ãã", 10001, IsError=true)>] member _.Length ((_: 'a, _: int, _: NotSet), _: int) : 'a * int * NotSet = failwith "oops!" member inline _.Run((start: int, end_: int, _: NotSet)) = fun (str: string) -> str.Substring(start, end_ - start) member inline _.Run((start: int, _: NotSet, length: int)) = fun (str: string) -> str.Substring(start, length) let substring = SubstringBuilder ()
*1:startã«ãend_ã«ãå®æ°ãæå®ãã¦ãããããSubstringã®ç¬¬2å¼æ°ãè¨ç®ããã¦ãã¯ãå®æ°ã«ãªã£ã¦ãã¾ã
*2:'aãintã«ãªã£ã¦ããã®ã¯ãb.Startã«ãã£ã¦'aãintã«åºå®åããããã
*3:ä¾å¤ãæããã«ãå¼æ°ããã®ã¾ã¾è¿ãããã«ãã¦ã大ä¸å¤«ã§ã
ã³ã³ãã¥ãã¼ã·ã§ã³å¼ã§ãã¼ã¯ã¼ãå¼æ°
ããã¯F# Advent Calendar 2021ã®23æ¥åã®è¨äºã§ãã
ãã®éã®ç¬¬3å FUN FAN F#ã«åå ããã¨ãããã«ã¹ã¿ã ãªãã¬ã¼ã¿ã¼ããã¼ã¯ã¼ãå¼æ°ã®ããã«ä½¿ã£ã¦ããã®ãã¿ã¦æãã¤ãããã¿ãç´¹ä»ãã¾ãã ããã¾ã§ãã¿ã§ãã®ã§ãå®éã«ãã®ãããªAPIãæä¾ããã®ãã©ããã®å¤æã¯åèªã«ä»»ãã¾ãã
ã«ã¹ã¿ã ãªãã¬ã¼ã¿ã¼ã®èª¬æã¯ãã«ã¹ã¿ã ãªãã¬ã¼ã·ã§ã³ãã³ãºãªã³ãªã©ãåèã«ãã¦ããã ãã¨ãã¦ãä»åç®æãã®ã¯ä»¥ä¸ã®ãããªAPIã§ãã
let str = "F# Advent Calendar 2021" let res1 = str |> substring { start 3; end_ 9 } let res2 = str |> substring { start 19; length 4 } printfn "%s, %s" res1 res2 // => Advent, 2021
ããã ãã ã¨ã¤ã¾ããªãã®ã§ã次ã®ãããªãã®ã¯ã³ã³ãã¤ã«ã¨ã©ã¼ã«ãããã§ãã
// end_ã¨lengthã¯ä¸¡æ¹æå®ã§ããªãããã«ããã substring { start 3; end_ 9; length: 10 } // startããªãã¨ã¨ã©ã¼ã«ããã substring { end_ 9 } // åããã¼ã¯ã¼ããè¤æ°æå®ãã¦ã»ãããªã substring { start 3; end_ 9; start: 4 }
ã¾ããé ä¸åã«ãããã§ãããã
// 次ã®2ã¤ã¯åã substring { start 3; end_ 9 } substring { end_ 9; start 3 }
èãæ¹
ã³ã³ãã¥ãã¼ã·ã§ã³å¼ã§ã¯ãRun
ãæä¾ãããã¨ã§ã³ã³ãã¥ãã¼ã·ã§ã³å¼ã§çµã¿ç«ã¦ãçµæã Run
ã®å¼æ°ã«æ¸¡ããããã«ãªãã¾ãã
ã¨ãããã¨ã§ãRun
ããªã¼ãã¼ãã¼ããã¦åã«ãã£ã¦å¦çãåãåããã¨ãããã¨ãã§ãã¾ãã
ããã¦ãã«ã¹ã¿ã ãªãã¬ã¼ã·ã§ã³ã§è¨±ãããçµã¿åãããåã§æå®ã§ããã°ããã以å¤ã®çµã¿åããã¯ã¨ã©ã¼ã«ã§ãã¾ãã ãã®æ¹éã§ä½ã£ã¦ããã¾ãã
ä½ãæ¹
ã¾ãã¯ãè¨å®ããã¦ããªããã¼ã¯ã¼ãã表ãåãç¨æãã¾ãã
type NotSet = NotSet
次ã«ãã«ã¹ã¿ã ãªãã¬ã¼ã·ã§ã³ã使ãã®ã§ããã«ãã¼ã¯ã©ã¹ã« Yield
ãå¿
è¦ã§ãã
member _.Yield (()) = (NotSet, NotSet, NotSet)
Yield
ã¯ã¿ãã«ãè¿ãããã«ãªã£ã¦ãã¦ãåããé ã« start
, end_
, length
ã«å¯¾å¿ãã¾ã*1ã
å½ç¶ãåæ段éã§ã¯ã©ã®ãã¼ã¯ã¼ããæå®ããã¦ããªãããããã¹ã¦ NotSet
ã§ãã
次ã«ãã«ã¹ã¿ã ãªãã¬ã¼ã·ã§ã³ãã¨ã«å¯¾å¿ããã¿ãã«ã®è¦ç´ ãæ´æ°ãã¾ãã ä¾ãã°ãããªæãã§ãã
[<CustomOperation("end_")>] member _.End((startParam: 'a, _: NotSet, lengthParam: NotSet), end_: int) = (startParam, end_, lengthParam)
ã¿ãã«ã®æåã®è¦ç´ (startParam
) 㯠end_
ãå¼ã³åºãåã§ãå¾ã§ãè¨å®ããã¦ãããã°ããã®ã§ããªãã§ãåãåããããã«ãã¦ãã¾ãã
ã¿ãã«ã®2çªç®ã®è¦ç´ ã¯ãend_
èªä½ã§ãã®ã§ãã㯠End
ã®ç¬¬2å¼æ°ã使ãããã使ãã¾ããã
ãªã®ã§ã_
ã§åãã¦ãã¾ãã
ã¾ããåã NotSet
ã«éå®ãã¦ãã¾ããããããéå®ããã« 'b
ã¨ãããã¨ã§ãä½åº¦ãè¨å®ã§ãã¦ãã¤å¾åã¡ã«ãªããããªAPIãæä¾ã§ãã¾ãã
ã¿ãã«ã®æå¾ã®è¦ç´ (lengthParam
)㯠NotSet
ã«éå®ãã¦ãã¾ãã
ããã¯ãend_
ãªãã¬ã¼ã¿ã¼ãå¼ã³åºãåã« length
ãªãã¬ã¼ã¿ã¼ãå¼ã³åºãã¦ããå ´åãã³ã³ãã¤ã«ã¨ã©ã¼ã«ãããããã§ãã
ãã®ããã«ã
- ãã®ãªãã¬ã¼ã¿ã¼ãå¼ã³åºãããå ´åã«ã¨ã©ã¼ã«ããããã¼ã¯ã¼ãã¯
NotSet
ãæå® - ãã®ãªãã¬ã¼ã¿ã¼ãå¼ã³åºãããå ´åã«ã¨ã©ã¼ã«ããããªããã¼ã¯ã¼ãã¯åãã©ã¡ã¼ã¿ã¼ãæå®
ãããã¨ã§ãå¤ãªçµã¿åãããå¼¾ããããã«ãã¦ãã¾ãã
æå¾ã«ãé©åãªçµã¿åããã®å ´åã«é©åãªå¦çããã Run
ãå®ç¾©ãã¦å®æã§ã*2ã
member _.Run((start: int, end_: int, _: NotSet)) = fun (str: string) -> str.Substring(start, end_ - start) member _.Run((start: int, _: NotSet, length: int)) = fun (str: string) -> str.Substring(start, length)
å ¨ä½
å ¨ä½ã¯ãããªæãã§ãã
type NotSet = NotSet type SubstringBuilder () = member _.Yield (()) = (NotSet, NotSet, NotSet) [<CustomOperation("start")>] member _.Start ((_: NotSet, endParam: 'b, lengthParam: 'c), start: int) = (start, endParam, lengthParam) [<CustomOperation("end_")>] member _.End ((startParam: 'a, _: NotSet, lengthParam: NotSet), end_: int) = (startParam, end_, lengthParam) [<CustomOperation("length")>] member _.Length ((startParam: 'a, endParam: NotSet, _: NotSet), length: int) = (startParam, endParam, length) member _.Run((start: int, end_: int, _: NotSet)) = fun (str: string) -> str.Substring(start, end_ - start) member _.Run((start: int, _: NotSet, length: int)) = fun (str: string) -> str.Substring(start, length) let substring = SubstringBuilder ()
ãã¿ã°ããï¼
ãæ°ã¥ãã®æ¹ãããããããã¾ããããããã¯åå®å ¨ãªBuilderãã¿ã¼ã³ãã³ã³ãã¥ãã¼ã·ã§ã³å¼ã§å解éãããã®ã§ããã åå¶ç´ã¨ã使ããªãã¦ããã®ã§ããªãªã¸ãã«ããã大åã·ã³ãã«ã«å®è£ ã§ãã¦ãããããªæ°ã¯ãã¾ãã
ä½è«
ä»æ¥ã§35æ³ã«ãªã£ã¦ãã¾ãã¾ããã ããã°ã©ãã®å®å¹´ãªã®ã§ãå¹´éãã ããã
追è¨
å¹çåã¨ã¨ã©ã¼ã¡ãã»ã¼ã¸ãæ¹è¯ãããã¼ã¸ã§ã³ã«ã¤ãã¦ã®è¨äºãæ¸ãã¾ããã
ããã°ã©ãã³ã°è¨èªã®æ§æã£ã¦å¤§äºã ãããã¨ãã話
Twitterã§ãããªã¤ã¶ããããã¾ããã
ããã°ã©ãã³ã°è¨èªã¨ãã¦ã®SQL(select)ã¨ããããã°ã©ãã³ã°è¨èªã¨ãã¦ã®XSLTã¨ãããã¨ãæ§æ大äºã£ã¦å®ææã¦ã¦ãªã¹ã¹ã¡ããªã¹ã¹ã¡ã¯ããªãã
— ããããç³»SQL (@bleis) 2021å¹´4æ24æ¥
ããã¡ãã£ã¨éãæãã«åãåãããããªãã¨æã£ãã®ã§è£è¶³ãã¾ãã
ãããã°ã©ãã³ã°è¨èªã¨ãã¦ã®ãã¨ã¯
ã¤ã¶ããã®ä¸ã§ãã¡ãã¡ãããã°ã©ãã³ã°è¨èªã¨ãã¦ã®ãã¨æ¸ããã®ã¯ã ãæ®éã®ãSQLããæ®éã®ãXSLTã¨ã¯éã£ã¦ãã¨ãããã¨ãæ示ãããã£ãããã§ãã
æ®éã¯SQLã¯ååãã®ããã®è¨èªã ããXSLTã¯XMLãå¤æããããã®è¨èª*1ã§ãã£ã¦ãJavaãC#ãªã©ã®ããã°ã©ãã³ã°è¨èªã¨åããããªãã®ã¨è¦ã¦ãã人ã¯ã»ã¼ããªãã§ãããã ãã ãã¡ãã£ã¨ãããã¯ããã¯ãç¥ã£ã¦ããã¨ããããã使ã£ã¦ãæ®éã®ãããã°ã©ãã³ã°è¨èªã§ãããããªå¦çãæ¸ãã¦ãã¾ãã®ã§ãã
XSLTã§ããã°ã©ãã³ã°
XSLTã«ã¯ã«ã¼ããåå²ãçµã¿è¾¼ã¾ãã¦ããã®ã§ãæç¶ãåããã°ã©ãã³ã°ã§ããã°ã©ãã¨ã§ããªãã¾ãã ãªãã¾ãããããã§ã¯é¢ç½ããªãã®ã§ã«ã¼ããå°å°ãã¦ã¿ã¾ãããã
ã«ã¼ãã使ããªãXSLTããã°ã©ãã³ã°
XSLTã§ã¯ template
ãé¢æ°ã¨ã¿ãªããã¨ã§ãã«ã¼ãã使ããªãã¦ãå帰å¼ã³åºãã使ãã¾ãã
ãã¨ã¯é«éé¢æ°ã使ããã°ãã£ããé¢æ°ããã°ã©ãã³ã°çãªãã®ãåºæ¥ã¾ããã
詳ãã説æ㯠ãã®ã¢ã¤ãã£ã¢ãå½¢ã«ãã人ãæ¸ããããã¥ã¡ã³ã ã«è²ãã¨ãã¦ã
ãã®ãã¯ããã¯ã使ããã¨ã§FizzBuzzã range
é¢æ°ã¨ map
é¢æ°ã¨ fizzbuzz
é¢æ°ãçµã¿åããããã¨ã§æ¸ãã¦ãã¾ãã¾ãã
é·ãã®ã§æãç³ã¿ã¾ããããããã¨åããããªãã¨ã F# ã§æ¸ãã¨ãããªãã¾ãã
let rec range from ``to`` = if from <= ``to`` then from :: range (from + 1) ``to`` else [] let rec map f = function | [] -> [] | x::xs -> f x :: map f xs let fizzbuzz n = if n % 15 = 0 then "FizzBuzz\n" elif n % 5 = 0 then "Buzz\n" elif n % 3 = 0 then "Fizz\n" else string n + "\n" let xs = range 1 100 xs |> map fizzbuzz |> List.iter (printf "%s")
大ä½æ©æ¢°çã«å¯¾å¿ã¯åããã¨æãã¾ãã
SQLã§ããã°ã©ãã³ã°
SQLã¯å帰ã¯ã¨ãªã¼ã«ãã£ã¦å帰ãæ¸ãã¾ãã ããããXSLTã¨ã¯éãé¢æ°ã«å¯¾å¿ããããããããªãã®ã(SELECTæã®ç¯çã§ã¯)ããã¾ããããé«éé¢æ°ãªã©å¤¢ã®ã¾ã夢ã§ãã ãã®ãããSQLã§ã®ããã°ã©ãã³ã°ã¯XSLTãããå°é£ã§ãã
ãã ãå帰ã¯ã¨ãªã¼ã§ã使ã WITH
ããå
¥ååºå®ã®é¢æ°ãã®ãããªãã®ã¨ã¿ãªããã¨ã§ãããç¨åº¦ã®æ§é åã¯å¯è½ã§ãã
-- æè¿PostgreSQLã使ã£ã¦ããã®ã§PostgreSQLæ³å® WITH RECURSIVE range_ (n_) AS ( SELECT 1 UNION ALL SELECT n_ + 1 FROM range_ WHERE n_ < 100 ) , fizzbuzz_ (n_, result_) AS ( SELECT n_ , CASE WHEN n_ % 15 = 0 THEN 'FizzBuzz' WHEN n_ % 5 = 0 THEN 'Buzz' WHEN n_ % 3 = 0 THEN 'Fizz' ELSE CAST(n_ AS varchar) END FROM range_ ) SELECT * FROM fizzbuzz_;
ããã«è¤éãªãã¨ããããå ´åã空ç½åºåããªã©ã®æååããªã¹ãã¨è¦ç«ã¦ã¦æä½ãããã¨ã§ãããããããªãã¨ãã§ããããã«ãªãã¾ã*2ã
æ§æã£ã¦å¤§äº
ãããªæãã§ãXSLTã§ããã°ã©ãã³ã°ãããã¨ããã¨å¤§éã®ãã¤ãºã§æ¬æ¥æ¸ãããå¦çã¯ã¿ã°ã®ä¸ã«åããã¦ãã¾ãã¾ããã SQL(select)ã§ããã°ã©ãã³ã°ãããã¨ããã¨ããããé¢æ°ãããã¦ãªãã®ã§èãæ¹ãããã¦å¤ããªãã¨ããã¾ãã(ãã®ããã®ä¾ã¨ãã¦ã¯FizzBuzzã¯å°ãããããã)ã SQLã§è¤éãªãã¤ã ã¨ã SQL で数式を評価 (完全版 + α) - ぐるぐる~ ãããããªã¹ã¹ã¡ã§ããæ°å¼è©ä¾¡ã ãã©ãæ¼ç®åã®åªå é ä½ãè¨å®å¯è½ãªå®å ¨ã«é ãããããã¤ã§ãã
ã¨ãããã¨ã§ãä»ã®äººã«ã¯ãã¾ããªã¹ã¹ã¡ã§ããªãããªã¹ã¹ã¡ã®æ§æã®ããããã¿ãä½æã§ããæ¹æ³ã§ããã å¶ç´ãããç°å¢ã§ããããèããã®ã好ããªäººã§ããã°ãããã¯ã»ã»ã»
F#ã®ãã¼ãµã¼ã«å¯¾ããæ¹è¯ãå ¥ãããï¼
F# Advent Calendar 2020ã®14æ¥ç®ã®ã¨ã³ããªã¼ã§ãã
ãããããã¿åãã§ãããä»å¾å ¥ããããããªãæ¹è¯ã®ç´¹ä»ã§ãã
RFC FS-1083
ãããå°å³ãªRFCã§ãããä»å¹´ã®F# Advent Calendarã§ããã£ãSRTP(Statically Resolved Type Parameters: éçã«è§£æ±ºãããåãã©ã¡ã¼ã¿ã¼)ã«é¢ããæ¹è¯ã§ãã
ç¾ç¶ã次ã®ã³ã¼ãã¯ã³ã³ãã¤ã«ã§ãã¾ããã
let inline f<^a>: ^a = failwith "error"
ç¾ç¶ã®F#ã§ã³ã³ãã¤ã«ãéãããã«ã¯ãã¾ã <
㨠^
ã®éã«ç©ºç½ãå
¥ãã < ^a>
ã¨ããå¿
è¦ãããã¾ãã
ããã¾ããæªãã®ã§ã >
ã®åã«ã空ç½ãå
¥ãã < ^a >
ãªã©ã¨ãã¾ãã
次ã«ã >
㨠:
ã®éã«ã空ç½ãå
¥ããå¿
è¦ãããã¾ãã
ã¤ã¾ãããããªãã³ã³ãã¤ã«ãéãã¾ãã
let inline f< ^a > : ^a = failwith "error" // æ®éã®åãã©ã¡ã¼ã¿ã¼ã®å ´åã¯æåã®ç©ºç½ã¯ä¸è¦ let g<'a> : 'a = failwith "error"
æåã®ç©ºç½ã®åé¡ã¯ã <^
ã¨ããæ¼ç®åãå®ç¾©ã§ããããã«ãããã <^
ãä¸ã¤ã®ãã¼ã¯ã³ã¨ãã¦æ±ã£ã¦ãã¾ãã®ãåå ã§ãã
ããããåãã©ã¡ã¼ã¿ã¼ã®ä½ç½®ã§ã¯åå²ãã¦æ±ããããã«ãã¼ãµã¼ãç´ãããã¨ããã®ãRFC FS-1083ã§ãã
äºã¤ç®ã®åé¡ã >:
ã¨ããä¸ã¤ã®ãã¼ã¯ã³ã¨ãã¦æ±ã£ã¦ãã¾ãç¹ã§ã¯åãåå *1ã§ãããRFC FS-1083ã®ç¯å²ã«ã¯å
¥ã£ã¦ããªãããã«ãè¦ãã¾ãã
ããããå°å³ã«é¢åãªåé¡ã解æ¶ããã¦ããã¨å¬ããã§ããã
nameofã®ç½
F# Advent Calendar 2020ã®11æ¥ç®ã®ã¨ã³ããªã¼ã§ãã
5æ¥ç®ã«ç¶ãã¦ã¾ã nameof
ã®è©±ã§ãã
nameof
ã«ã¯F#ã®ããã°ã©ã ã¨ãã¦ã¯å½ç¶ã ãã©å¿ããã¡ãªå¶ç´ãããã¾ãã
ä½ã®åé¡ããªãããã«è¦ãã¾ãããããã¯ã³ã³ãã¤ã«ã¨ã©ã¼ã§ãã
let f () = nameof f
ããããã¡ãªã®ã¯ã f
㯠f
ã®å®ç¾©æ¬ä½ã§ã¯ã¾ã è¦ããªãã®ã«åç
§ãããã¨ãã¦ããããã§ãã
let f x = match x with | 0 -> 0 | x -> f (x - 1) + x
ããããã¡ãªã®ã¨åãçç±ã§ããã
ãªã®ã§ããããããããã¨ãããããã°ã
let rec f () = nameof f
ã®ããã« rec
ãä»ããå¿
è¦ãããã¾ãã
å帰ãã¦ããªãã®ã« rec
ãä»ããã®ã¯æ°æã¡æªãæ°ããã¾ãããããã¯ä»æ¹ãªãã§ãããã
ã¡ãªã¿ã«ãã¡ã½ããã¯å®ç¾©æ¬ä½ã§èªåèªèº«ãè¦ããã®ã§ã次ã®ã³ã¼ãã¯ã³ã³ãã¤ã«ãéãã¾ãã
type t () = static member F() = nameof t.F
ãã¹ãããã¬ã³ã¼ãã®æ´æ°ã楽ã«ãªãããï¼
F# Advent Calendar 2020ã®9æ¥ç®ã®ã¨ã³ããªã¼ã§ãã
ä»æ¥ã¯(ãï¼)ãå ¥ãã¨å¬ããRFCã®è©±ã§ãã
RFC FS-1049
RFC FS-1049ã¯ã
ãã¹ãããã¬ã³ã¼ãã®ãã£ã¼ã«ãã with
ã§æ¸ãæããããããã«æ¡å¼µããããã¨ãããã®ã§ã*1ã
F#ã®ã¬ã³ã¼ã㯠with
ã使ããã¨ã§ãä¸é¨ã®ãã£ã¼ã«ãã®ã¿ãæ´æ°ããæ°ããã¬ã³ã¼ããä½ãã¾ãã
type Customer = { Name: string Address: string Age: int } // Nameã¨Addressã¯ãã®ã¾ã¾ã«Ageãã¤ã³ã¯ãªã¡ã³ãããé¢æ° let incrAge customer = { customer with Age = customer.Age + 1 }
ãããããã¹ãããã¬ã³ã¼ããæ´æ°ããããã«ã¯ with
ããã¹ããã¦ä½¿ãå¿
è¦ãããã¾ãã
ä¾ãã°ã
type A = { X: B } and B = { Y: C } and C = { Z: string } let a = { X = { Y = { Z = "str" } } }
ããããã¬ã³ã¼ãããã£ãå ´åã« Z
ãæ´æ°ããã«ã¯ã
let a' = { a with X = { a.X with Y = { a.X.Y with Z = "updated" } } }
ã®ããã«ããªããã°ãªãã¾ããã
RFC FS-1049ã¯ãããæ¸ããããã«ãããã¨ããææ¡ã§ãã
let a' = { a with X.Y.Z = "updated" }
ã¨ã¦ãã·ã³ãã«ã«ãªãã¾ãããã
ãã ããããã£ã¼ã«ãã option
ã¨ãã ã¨ããããçµå±ãã¹ããå¿
è¦ã§ãã
type A = { X: B } and B = { Y: C option } and C = { Z: string } let a = { X = { Y = Some { Z = "str" } } } let a' = { a with X.Y = a.X.Y.map(fun y -> { y with Z = "updated" }) }
ã¾ãã以åãã便å©ã«ãªããã¨ã¯ç¢ºå®ãªã®ã§ãå ¥ã£ã¦ã»ããæ¡å¼µã§ã¯ããã¾ããã
*1:ãã¨ãã¨ã®ææ¡ã¯ãããã¡ã¼ã¹ãã¯ã©ã¹ã®Lenså ¥ããããï¼ãã¨ãããã®ã ã£ãã®ã§å¤§åãã¨ãªããã¨ããã«çå°ããæã¯ããã¾ãã