{"id":889,"date":"2009-10-23T10:10:20","date_gmt":"2009-10-23T08:10:20","guid":{"rendered":"http:\/\/www.navision-blog.de\/2009\/10\/23\/using-monads-in-f-part-i-the-state-monad\/"},"modified":"2009-10-23T10:45:38","modified_gmt":"2009-10-23T08:45:38","slug":"using-monads-in-fsharp-part-i-the-state-monad","status":"publish","type":"post","link":"http:\/\/www.navision-blog.de\/blog\/2009\/10\/23\/using-monads-in-fsharp-part-i-the-state-monad\/","title":{"rendered":"Using monads in F# &ndash; Part I: The State Monad"},"content":{"rendered":"<p>Currently I\u2019m trying to implement some of the <a href=\"http:\/\/www.haskell.org\/all_about_monads\/html\/introII.html\">standard monads<\/a> in F#. If you want to read about the theory behind monads and their implementation (in Haskell) it\u2019s a good start to look into \u201c<a href=\"http:\/\/www.haskell.org\/all_about_monads\/html\/index.html\">All about Monads<\/a>\u201d on <a href=\"http:\/\/www.haskell.org\">haskell.org<\/a>.<\/p>\n<p>In this blog post series I don\u2019t care about mathematical details. Instead I will try to show how monads can help to simplify our code.<\/p>\n<h5>Motivation<\/h5>\n<p>We have a generic binary tree with some test data:<\/p>\n<div style=\"font-family: courier new; background: white; color: black; font-size: 10pt\">\n<p style=\"margin: 0px\"><span style=\"color: blue\">type<\/span> Tree&lt;&#8216;a&gt; =<\/p>\n<p style=\"margin: 0px\">| Leaf <span style=\"color: blue\">of<\/span> &#8216;a<\/p>\n<p style=\"margin: 0px\">| Branch <span style=\"color: blue\">of<\/span> Tree&lt;&#8216;a&gt; * Tree&lt;&#8216;a&gt;&#160; <\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> tree =<\/p>\n<p style=\"margin: 0px\">&#160; Branch(<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160; Leaf <span style=\"color: maroon\">&quot;Max&quot;<\/span>,<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160; Branch(<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; Leaf <span style=\"color: maroon\">&quot;Bernd&quot;<\/span>,<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; Branch(<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Branch(<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf <span style=\"color: maroon\">&quot;Holger&quot;<\/span>,<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf <span style=\"color: maroon\">&quot;Ralf&quot;<\/span>),<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Branch(<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf <span style=\"color: maroon\">&quot;Kerstin&quot;<\/span>,<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf <span style=\"color: maroon\">&quot;Steffen&quot;<\/span>))))<\/p>\n<\/p><\/div>\n<p>If we want to print this tree we can use the following recursive function:<\/p>\n<div style=\"font-family: courier new; background: white; color: black; font-size: 10pt\">\n<p style=\"margin: 0px\"><span style=\"color: green\">\/\/\/ prints a binary tree<\/span><\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> printTree t =<\/p>\n<p style=\"margin: 0px\">&#160; <span style=\"color: blue\">let<\/span> <span style=\"color: blue\">rec<\/span> print t level&#160; =<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160; <span style=\"color: blue\">let<\/span> indent = <span style=\"color: blue\">new<\/span> String(<span style=\"color: maroon\">&#8216; &#8216;<\/span>, level * 2)<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160; <span style=\"color: blue\">match<\/span> t <span style=\"color: blue\">with<\/span><\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160; | Leaf l <span style=\"color: blue\">-&gt;<\/span> printfn <span style=\"color: maroon\">&quot;%sLeaf: %A&quot;<\/span> indent l<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160; | Branch (left,right) <span style=\"color: blue\">-&gt;<\/span> <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; printfn <span style=\"color: maroon\">&quot;%sBranch:&quot;<\/span> indent<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; print left (level+1)<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; print right (level+1)<\/p>\n<p style=\"margin: 0px\">&#160; print t 0<\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<p style=\"margin: 0px\">printfn <span style=\"color: maroon\">&quot;Unlabeled:&quot;<\/span><\/p>\n<p style=\"margin: 0px\">printTree tree&#160; <\/p>\n<\/p><\/div>\n<p>And what we get is something like this:<\/p>\n<div style=\"font-family: courier new; background: white; color: black; font-size: 10pt\">\n<p style=\"margin: 0px\">Unlabeled:<\/p>\n<p style=\"margin: 0px\">Branch:<\/p>\n<p style=\"margin: 0px\">&#160; Leaf: &quot;Max&quot;<\/p>\n<p style=\"margin: 0px\">&#160; Branch:<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160; Leaf: &quot;Bernd&quot;<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160; Branch:<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; Branch:<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf: &quot;Holger&quot;<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf: &quot;Ralf&quot;<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; Branch:<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf: &quot;Kerstin&quot;<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf: &quot;Steffen&quot;<\/p>\n<\/p><\/div>\n<h5>Labeling the tree with mutable state<\/h5>\n<p>Now we want to give every tree a unique label. This can be easily done by another recursive function:<\/p>\n<div style=\"font-family: courier new; background: white; color: black; font-size: 10pt\">\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> <span style=\"color: blue\">mutable<\/span> label = -1 <\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> <span style=\"color: blue\">rec<\/span> labelTreeMS t =<\/p>\n<p style=\"margin: 0px\">&#160; <span style=\"color: blue\">match<\/span> t <span style=\"color: blue\">with<\/span><\/p>\n<p style=\"margin: 0px\">&#160; | Leaf l <span style=\"color: blue\">-&gt;<\/span> <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; label &lt;- label + 1 <span style=\"color: green\">\/\/ changing the state<\/span><\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; Leaf(l,label)&#160; <\/p>\n<p style=\"margin: 0px\">&#160; | Branch(oldL,oldR) <span style=\"color: blue\">-&gt;<\/span> <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let<\/span> newL = labelTreeMS oldL<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let<\/span> newR = labelTreeMS oldR<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; Branch(newL,newR)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> treeMS = labelTreeMS tree<\/p>\n<p style=\"margin: 0px\">printfn <span style=\"color: maroon\">&quot;Labeled (with global mutable state):&quot;<\/span><\/p>\n<p style=\"margin: 0px\">printTree treeMS&#160;&#160;&#160;&#160;&#160; <\/p>\n<\/p><\/div>\n<p>And the output would look like this:<\/p>\n<div style=\"font-family: courier new; background: white; color: black; font-size: 10pt\">\n<p style=\"margin: 0px\">Labeled (with global mutable state):<\/p>\n<p style=\"margin: 0px\">Branch:<\/p>\n<p style=\"margin: 0px\">&#160; Leaf: (&quot;Max&quot;, 0)<\/p>\n<p style=\"margin: 0px\">&#160; Branch:<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160; Leaf: (&quot;Bernd&quot;, 1)<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160; Branch:<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; Branch:<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf: (&quot;Holger&quot;, 2)<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf: (&quot;Ralf&quot;, 3)<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; Branch:<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf: (&quot;Kerstin&quot;, 4)<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; Leaf: (&quot;Steffen&quot;, 5)<\/p>\n<\/p><\/div>\n<p>The only problem with <strong>labelTreeMS<\/strong> is that it uses global state, which is very bad because we can\u2019t be sure if the mutable label variable is changed (from maybe another thread) or not.<\/p>\n<h5>Labeling the tree without global state<\/h5>\n<p>If we want to remove this side effect, we can pass the state directly into the function:<\/p>\n<div style=\"font-family: courier new; background: white; color: black; font-size: 10pt\">\n<p style=\"margin: 0px\"><span style=\"color: green\">\/\/ non-monadic version<\/span><\/p>\n<p style=\"margin: 0px\"><span style=\"color: green\">\/\/ passing the state around explicitly<\/span><\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> <span style=\"color: blue\">rec<\/span> labelTreeNM t s =<\/p>\n<p style=\"margin: 0px\">&#160; <span style=\"color: blue\">match<\/span> t <span style=\"color: blue\">with<\/span><\/p>\n<p style=\"margin: 0px\">&#160; | Leaf l <span style=\"color: blue\">-&gt;<\/span> s+1,Leaf(l,s)&#160; <span style=\"color: green\">\/\/ changing the state<\/span><\/p>\n<p style=\"margin: 0px\">&#160; | Branch(oldL,oldR) <span style=\"color: blue\">-&gt;<\/span> <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let<\/span> stateL,newL = <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; labelTreeNM oldL s<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let<\/span> stateR,newR = <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; labelTreeNM oldR stateL&#160; <span style=\"color: green\">\/\/ passing the state around<\/span><\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; stateR,Branch(newL,newR)&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> _,treeNM = labelTreeNM tree 0<\/p>\n<p style=\"margin: 0px\">printfn <span style=\"color: maroon\">&quot;Labeled (non-monadic):&quot;<\/span><\/p>\n<p style=\"margin: 0px\">printTree treeNM<\/p>\n<\/p><\/div>\n<h5><\/h5>\n<h5>Labeling the tree by using the State Monad<\/h5>\n<p>With the help of the State Monad we get a very similar function:<\/p>\n<div style=\"font-family: courier new; background: white; color: black; font-size: 10pt\">\n<p style=\"margin: 0px\"><span style=\"color: green\">\/\/\/ labels a tree by using the state monad <\/span><\/p>\n<p style=\"margin: 0px\"><span style=\"color: green\">\/\/\/ (uses F#\u2019s sugared syntax)<\/span><\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> <span style=\"color: blue\">rec<\/span> labelTree t = state {<\/p>\n<p style=\"margin: 0px\">&#160;&#160; <span style=\"color: blue\">match<\/span> t <span style=\"color: blue\">with<\/span><\/p>\n<p style=\"margin: 0px\">&#160;&#160; | Leaf l <span style=\"color: blue\">-&gt;<\/span> <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let!<\/span> s = getState<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">do!<\/span> setState (s+1)&#160; <span style=\"color: green\">\/\/ changing the state<\/span><\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">return<\/span> Leaf(l,s)<\/p>\n<p style=\"margin: 0px\">&#160;&#160; | Branch(oldL,oldR) <span style=\"color: blue\">-&gt;<\/span><\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let!<\/span> newL = labelTree oldL <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let!<\/span> newR = labelTree oldR <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">return<\/span> Branch(newL,newR)}<\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<p style=\"margin: 0px\">printfn <span style=\"color: maroon\">&quot;Labeled (monadic):&quot;<\/span><\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> treeM = Execute (labelTree tree) 0<\/p>\n<p style=\"margin: 0px\">printTree treeM<\/p>\n<\/p><\/div>\n<p>Thanks to the F# sugared syntax this <strong>labelTree<\/strong> and <strong>labelTreeMS <\/strong>are visually nearly the same. Every time we are dealing with state we use the exclamation mark. There is only one point (in the Leaf case) where have to use (and change) the state. <\/p>\n<p>The nice thing is, that we can write the function like the first version, but we don\u2019t have to perform the side effect on the shared state.<\/p>\n<p>If we want to use the de-sugared version we have to write it like this:<\/p>\n<div style=\"font-family: courier new; background: white; color: black; font-size: 10pt\">\n<p style=\"margin: 0px\"><span style=\"color: green\">\/\/\/ labels a tree and uses de-sugared syntax<\/span><\/p>\n<p style=\"margin: 0px\"><span style=\"color: green\">\/\/\/ (implementation looks different to labelTreeNM)<\/span><\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> <span style=\"color: blue\">rec<\/span> labelTreeDesugared t =<\/p>\n<p style=\"margin: 0px\">&#160;&#160; <span style=\"color: blue\">match<\/span> t <span style=\"color: blue\">with<\/span><\/p>\n<p style=\"margin: 0px\">&#160;&#160; | Leaf l <span style=\"color: blue\">-&gt;<\/span> (<span style=\"color: blue\">fun<\/span> s <span style=\"color: blue\">-&gt;<\/span> Leaf(l,s),(s+1))<\/p>\n<p style=\"margin: 0px\">&#160;&#160; | Branch(oldL,oldR) <span style=\"color: blue\">-&gt;<\/span> <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160; labelTreeDesugared oldL &gt;&gt;=<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; (<span style=\"color: blue\">fun<\/span> newL <span style=\"color: blue\">-&gt;<\/span> <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; labelTreeDesugared oldR &gt;&gt;= <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; (<span style=\"color: blue\">fun<\/span> newR <span style=\"color: blue\">-&gt;<\/span> <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Branch(newL,newR) |&gt; returnS))&#160;&#160;&#160; <\/p>\n<\/p><\/div>\n<h5>State monad implementation<\/h5>\n<p>In order to use the state monad, of course we have to implement it first. Here is my version, which allows to use the de-sugared and sugared version:<\/p>\n<div style=\"font-family: courier new; background: white; color: black; font-size: 10pt\">\n<p style=\"margin: 0px\"><span style=\"color: blue\">module<\/span> StateMonad<\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> (&gt;&gt;=) x f = <\/p>\n<p style=\"margin: 0px\">&#160;&#160; (<span style=\"color: blue\">fun<\/span> s0 <span style=\"color: blue\">-&gt;<\/span> <\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let<\/span> a,s = x s0<\/p>\n<p style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; f a s)&#160;&#160;&#160;&#160;&#160;&#160; <\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> returnS a = (<span style=\"color: blue\">fun<\/span> s <span style=\"color: blue\">-&gt;<\/span> a, s)<\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">type<\/span> StateBuilder() =<\/p>\n<p style=\"margin: 0px\">&#160; <span style=\"color: blue\">member<\/span> m.Bind(x, f) = x &gt;&gt;= f<\/p>\n<p style=\"margin: 0px\">&#160; <span style=\"color: blue\">member<\/span> m.Return a = returnS a <\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> state = <span style=\"color: blue\">new<\/span> StateBuilder()<\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> getState = (<span style=\"color: blue\">fun<\/span> s <span style=\"color: blue\">-&gt;<\/span> s, s)<\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> setState s = (<span style=\"color: blue\">fun<\/span> _ <span style=\"color: blue\">-&gt;<\/span> (),s)&#160; <\/p>\n<p style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> Execute m s = m s |&gt; fst<\/p>\n<p style=\"margin: 0px\">&#160;<\/p>\n<\/p><\/div>\n<p>If you want to learn more about the State Monad I recommend watching Brian Beckman&#8217;s Channel 9 video \u201c<a href=\"http:\/\/channel9.msdn.com\/shows\/Going+Deep\/Brian-Beckman-The-Zen-of-Expressing-State-The-State-Monad\/\">The Zen of Stateless State &#8211; The State Monad<\/a>&quot;.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Currently I\u2019m trying to implement some of the standard monads in F#. If you want to read about the theory behind monads and their implementation (in Haskell) it\u2019s a good start to look into \u201cAll about Monads\u201d on haskell.org. In this blog post series I don\u2019t care about mathematical details. Instead I will try to [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[448],"tags":[664,582,581],"_links":{"self":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/889"}],"collection":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/comments?post=889"}],"version-history":[{"count":12,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/889\/revisions"}],"predecessor-version":[{"id":901,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/889\/revisions\/901"}],"wp:attachment":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/media?parent=889"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/categories?post=889"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/tags?post=889"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}