如何在Haskell中编写多函数(可变数量的参数)

时间:2020-07-04 17:17:03

标签: haskell typeclass

我一直在努力尝试在Development.Shake.cmd的行上编写多arar函数,但是即使经过3天8次不同的尝试,我仍然无法对此进行编译。

这是我设法完成的事情:

{-# LANGUAGE ExtendedDefaultRules #-}

--
-- this is for an i18n system integrated with Lucid
-- where I want the `t_` function to work with a variable number of arguments
--

module Try4 where

import Lucid (HtmlT, div_, toHtmlRaw)
import Control.Monad.Trans (lift)
import Data.Text as T

default (Text)


newtype Translation = Translation { rawTranslation :: Text }

class (Monad m) => HasI18n m where
  fetchTranslation :: Text -> m Translation

class (HasI18n m) => InterpolationValue m a where
  -- the reason why this function is not pure, is because it is possible
  -- for the conversion function to depend on the monadic context. For example,
  -- it is not necessary that date/time values are always converted to text using
  -- the same format. The format to be used could be part of the monadic context.
  interpolationVal :: a -> m Text

class Interpolate arg result where
  t_ :: arg -> result

instance (HasI18n m, a ~ ()) => Interpolate Text (HtmlT m a) where
  t_ k = do
    x <- lift $ fetchTranslation k
    toHtmlRaw $ rawTranslation x

instance (HasI18n m, InterpolationValue m v, a ~ ()) => (Interpolate Text ((Text, v) -> HtmlT m a)) where
  t_ k (i, v) = do
    x <- lift $ fetchTranslation k
    val <- lift $ interpolationVal v
    toHtmlRaw $ applySingleInterpolation (rawTranslation x) (i, val)

instance (HasI18n m) => InterpolationValue m Text where
  interpolationVal = pure

instance (HasI18n m) => InterpolationValue m Int where
  interpolationVal = pure . T.pack . show

applySingleInterpolation :: Text -> (Text, Text) -> Text
applySingleInterpolation memo (k, v) = T.replace ("%{" <> k <> "}") v memo

myHtml :: (HasI18n m) => HtmlT m ()
myHtml = div_ $ do
  div_ $ t_ "some.i18n.key"
  div_ $ t_ "some.18n.key" ("interpolation1", "some-string")

最后,这就是我遇到的问题。如何编写(递归)类型类实例以使以下内容得以编译?无论我做什么,我都无法统一mInterpolationValue m a中的HtmlT m a。不知何故,由于Interpolate arg result,GHC似乎感到困惑,并推断出不同的m1m2

t_ "some.18n.key" 
   ("interpoliation1", "some-string") 
   ("interpolation2", 10 :: Int)
   ("interpolation3", fromGregorian 2020 1 1)

1 个答案:

答案 0 :(得分:0)

我建议从复制Text.Printf开始,并逐步对其进行修改,直到获得所需的内容。那是从中复制Shake版本的纯净来源。重要的实例是:

instance (PrintfArg a, PrintfType r) => PrintfType (a -> r) where
instance (a ~ ()) => PrintfType (IO a) where

那是一个归纳实例,一个终端实例。

相关问题