像replicateM一样复制A的方法?

时间:2014-10-09 18:57:01

标签: haskell applicative

有:

getSdr = Sdr <$> u1 <*> u1 <*> u1 <*> getU1List <*> mcn <*> mcn␣
             <*> mcn <*> mcn <*> mcn <*> mcn <*> mcn <*> mcn <*> mcn
             <*> mcn <*> mcn <*> mcn <*> mcn <*> mcn <*> mcn <*> mcn

想要:

getSdr = Sdr <$> u1 <*> u1 <*> u1 <*> getU1List <*> replicateA 16 mcn

我确实注意到replicateA中的Data.Sequence,但我不知道该图书馆,或者它是否可以在这里提供帮助。它不会进行类型检查,因为它是

replicateA :: Applicative f => Int -> f a -> f (Seq a)

似乎没有逃脱Seq

澄清一下,Sdr是一个记录:

   | Sdr { sdrHeadNum :: !U1
          , sdrSiteGrp :: !U1
          -- , siteCount :: !U1
          , siteNums :: [U1]
          , handlerType :: Maybe Text
          , handlerId :: Maybe Text
          , probeCardType :: Maybe Text
          , probeCardId :: Maybe Text
          , loadBoardType :: Maybe Text
          , loadBoardId :: Maybe Text
          , dibType :: Maybe Text
          , dibId :: Maybe Text
          , cableType :: Maybe Text
          , cableId :: Maybe Text
          , contactorType :: Maybe Text
          , contactorId :: Maybe Text
          , laserType :: Maybe Text
          , laserId :: Maybe Text
          , extraType :: Maybe Text
          , extraId :: Maybe Text }

它是所有数据类型的母亲的一部分:https://github.com/gitfoxi/Stdf/blob/WIP/Data/Stdf/Types.hs

3 个答案:

答案 0 :(得分:6)

这个答案需要疯狂的笑声。我不打算输出那部分;你只需要想象。

在惯用的Haskell中你想要的是不可能的。你想要的可能是一个坏主意。但你想要的并不是完全不可能的。

第一个警告标志:我们需要大量的编译器扩展。我想,只有最后一个不是严格要求的。 (这整个答案假设GHC 7.8;我认为它可以调整为7.6。)

{-# LANGUAGE TypeFamilies, DataKinds, MultiParamTypeClasses, 
    FlexibleInstances, ScopedTypeVariables, NoMonomorphismRestriction #-}
module Maniacal where
import Control.Applicative
import Data.Proxy

以疯狂的方式,我会先说清楚:

getSdr :: Applicative f => f Sdr
getSdr = Sdr <$> u1 <*> u1 <*> u1 <*> getU1List # starN sixteen mcn

ghci> getSdr :: [Sdr]
[Sdr A A A B C C C C C C C C C C C C C C C C]
ghci> :type starN sixteen mcn
{- something hideous -}

但是怎么样?! (顺便说一句,Sdr等的样板定义位于最底层。)

首先,我们需要一个类型级别16,我们可以在递归类型类中使用它。 (GHC的花式类型数字不支持7.8的归纳,在这里没用。)

data PInt = One | S PInt -- Promoted to types
type Sixteen = S (S (S (S (S (S (S (S (S (S (S (S (S (S (S One))))))))))))))
sixteen :: Proxy Sixteen
sixteen = Proxy

在大锅里我们扔了一个疯狂的类型。

class MultiStar (n :: PInt) a b where
  type MultiStarT n a b :: *
  starN :: Applicative f => proxy n -> f a -> f (MultiStarT n a b) -> f b

instance MultiStar One a b where
  type MultiStarT One a b = a -> b
  starN _ v f = f <*> v

instance (MultiStar n a b, (MultiStarT n a b) ~ (a -> t0))
       => MultiStar (S n) a b where
  type MultiStarT (S n) a b = a -> MultiStarT n a b
  starN _ v f = starN (Proxy :: Proxy n) v (addOne <$> f)
    where addOne g x = g x x

不要问我约束中的相等性。

最后,有点语法精神:

(#) = flip ($)
infixl 4 #

我们已经完成了!现在只是样板。 (或者它应该是釜板吗?)和疯狂的笑声。

data A = A deriving Show
data B = B deriving Show
data C = C deriving Show
data Sdr = Sdr A A A B C C C C C C C C C C C C C C C C deriving Show
u1 = pure A
getU1List = pure B
mcn = pure C

答案 1 :(得分:2)

我不认为你想要的是可能的。添加parens并简化:

getSdr = (((Sdr <$> u1) <*> u1) <*> u1) -- ...

这些运算符组在左侧(infixl)和&lt; *&gt;不是关联的,所以你不能只替换右手边。

即使你可以,这种类型是什么?让我们说:

 data Sdr = Sdr Int Int Char Char Char
 u1 :: Parser Int
 mcn :: Parser Char
 getSdr :: Parser Sdr
 getSdr = Sdr <$> u1 <*> u1 <*> mcn <*> mcn <*> mcn

您希望用以下内容替换mcn部分:

 getSdr = Sdr <$> u1 <*> u1 <*> mcn3

但第一部分的类型是:

 Sdr <$> u1 <*> u1 :: Parser (Char -> Char -> Char -> Sdr)

您无法使用&lt; *&gt;将其应用于获得Parser Sdr的东西。

答案 2 :(得分:2)

您可以使用
制作replicateA功能 sequenceA :: (Traversable t, Applicative f) => t (f a) -> f (t a)
它允许您通过Traversable传递Applicative仿函数。

(差不多,Traversable意味着sequenceA有效。[]肯定是可以穿越的。)

import Data.Traversable (sequenceA)

replicateA :: Applicative f => Int -> f a -> f [a]
replicateA n x = sequenceA (replicate n x)

这意味着您可以(例如)replicateA 16 mcn :: Get [Text],但它不能使用您的数据构造函数。你可能需要选择重写你的构造函数或放弃replicateA,我担心。