【結論】Textの中のStringにmap :: String -> StringするにはProfunctorが一番!
起
ときどきTextにpack,unpackを介してString -> Stringしたくなるシチュエーションに出会う。 でも普通に関数合成すると、なんだか格好悪いんだよね。
{-# LANGUAGE OverloadedStrings #-}
import Data.Char (toUpper)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
-- Data.TextのtoUpperを使えとか言っちゃだめ! そしたら別の適切な例を教えて!
upper :: String -> String
upper = map toUpper
x :: Text
x = "nico"
main :: IO ()
main = do
let niconico = T.pack . upper $ T.unpack x -- 格好悪い
TIO.putStrLn niconico結
Profunctorのdimapを使う。
(->)Profunctorを使えばdomainとcodomainの変更を一気にできるので、
Text -> StringとString -> StringとString -> Textを格好良くできる!(まあ中身は👆と全くおんなじなんだけどでも見栄えいい)
これはその型と同型の型への操作に一般化できますので、newtypeにも応用できます。
{-# LANGUAGE OverloadedStrings #-}
import Data.Char (toUpper)
import Data.Profunctor (dimap)
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
upper :: String -> String
upper = map toUpper
x :: Text
x = "nico"
main :: IO ()
main = do
let niconico = dimap T.unpack T.pack upper x -- 平坦な構文に見えるので、見やすい
TIO.putStrLn niconico-- newtype Identity a = Identity { runIdentity :: a }
dimap runIdentity Identity f xその他
- Foundation.Collection InnerFunctor - Hackage
- 最初に考えたアプローチがちょうどこれで、でもTextのインスタンスがなかった
- Data.MonoTraversable - MonoFunctor - Hackage
InnerFunctorと全く同じアプローチでTextインスタンスもある、けどElementがCharだった。 普通に考えればそうだよねTextのnewtypeを作ってもいいけど、それならpack,unpackした方が早いと思ったのでやめた

