buildQueryString函数的Purescript类型

时间:2017-06-26 10:56:30

标签: purescript

我是Purescript的新手,我正在尝试编写一个函数 可以获取任何记录值并迭代字段和值并构建 一个查询字符串。

我想的是:

buildQueryString :: forall a. PropertyTraversible r => r -> String

我想这样使用:

buildQueryString {name: "joe", age: 10}      -- returns: "name=joe&age=10"

有没有办法在Purescript中用现有的习语写出类似的东西,还是我必须为此创建自己的自定义类型?

2 个答案:

答案 0 :(得分:2)

我确信它可以更短,但这是我基于purescript-generic-rep的实现(受genericShow启发)。此解决方案使用类型类 - 它似乎是generic-rep的标准方法:

module Main where

import Prelude

import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Console (CONSOLE, log)
import Data.Foldable (intercalate)
import Data.Generic.Rep (class Generic, Constructor(..), Field(..), Product(..), Rec(..), from)
import Data.Symbol (class IsSymbol, SProxy(..), reflectSymbol)

class EncodeValue a where
  encodeValue ∷ a → String

instance encodeValueString ∷ EncodeValue String where
  encodeValue = id

instance encodeValueInt ∷ EncodeValue Int where
  encodeValue = show

class EncodeFields a where
  encodeFields :: a -> Array String

instance encodeFieldsProduct
  ∷ (EncodeFields a, EncodeFields b)
  ⇒ EncodeFields (Product a b) where

  encodeFields (Product a b) = encodeFields a <> encodeFields b

instance encodeFieldsField
  ∷ (EncodeValue a, IsSymbol name)
  ⇒ EncodeFields (Field name a) where

  encodeFields (Field a) =
    [reflectSymbol (SProxy :: SProxy name) <> "=" <> encodeValue a]

buildQueryString
  ∷ ∀ a l n.
    Generic n (Constructor l (Rec a))
  ⇒ (EncodeFields a)
  ⇒ n
  → String
buildQueryString n =
  build <<< from $ n
 where
  build (Constructor (Rec fields)) = intercalate "&" <<< encodeFields $ fields

newtype Person =
  Person
    { name   ∷ String
    , age    ∷ Int
    }
derive instance genericPerson ∷ Generic Person _

joe ∷ Person
joe = Person { name: "joe", age: 10 }

main :: forall e. Eff (console :: CONSOLE | e) Unit
main = do
  log <<< buildQueryString $ joe

buildQueryString期望包含记录的单个构造函数的类型值(可能只是newtype),因为无法为“展开的”Generic派生Record个实例类型。

如果您还要处理Array值等,那么encodeValue应该返回Array String类型的值。

答案 1 :(得分:0)

这可以通过purescript-generics实现,但它仅适用于名义类型,而不适用于任何记录。但它可以为您节省样板,因为您可以为<%= object.dateofbirth %>派生实例,因此它可以与任何数据 newtype 一起使用而无需进一步修改。

下行是,你必须对类型做一些假设:比如它只包含一条记录而且记录不包含数组或其他记录。

这是一个hacky演示如何工作:

Generic
purescript-generics-rep是更新的,所以可能有一个更好的解决方案,甚至可能在任何记录上。我还没试过(还)。