2014-10-27 20 views
1

在Haskell语法中,我们可以有一个(抽象)类型,如[a -> b],它是函数a到b的列表。具体的类型是[Int -> Int],比如map (*) [1..10]。是否有可能有一个类似[a -> b, b -> c, c -> d, ...]类型的级联函数列表?列表中的各个元素都是不同的(我认为),所以我不认为这是可能的。但是依赖类型可能吗?它的类型签名是什么(最好是伪哈斯克尔语法)?级联函数列表的类型是什么?

+0

你不能做到这一点与在Haskell平原名单,但它是可能的。查看HList库以获取异构列表。要警告的是,该库有很多扩展来获得这种动态行为。 – bheklilr 2014-10-27 17:27:53

+0

看看http://stackoverflow.com/questions/26565306/how-to-define-a-multiple-composition-function .... – jamshidh 2014-10-27 17:34:08

+1

这是一个(问题jamshidh链接的一个子集)的重复。然而,这个问题更直接地说明了这个问题。 – 2014-10-27 18:07:23

回答

6

你不能做到这一点与普通的名单,但你可以构建自己的列表类似的类型,如下所示:

{-# LANGUAGE GADTs #-} 

data CascadingList i o where 
    Id :: CascadingList i i 
    Cascade :: (b -> o) -> CascadingList i b -> CascadingList i o 

然后可以按如下方式使这些CascadingList S:

addOnePositive :: CascadingList Int Bool 
addOnePositive = Cascade (>0) $ Cascade (+1) $ Id 

你可以 '塌陷' 的名单:

collapse :: CascadingList a b -> a -> b 
collapse Id = id 
collapse (Cascade f c) = f . collapse c 

然后,你将不得不

collapse addOnePositive 0 == True 

请注意,这不考虑中间函数的类型,因此它可能不是您要查找的内容。


我刚刚意识到这与[c - > d,b - > c,a - > b]更接近。让它更接近你的意图是一个容易的改变;我可以编辑它,但我认为你明白了。

+1

正如我在[回答上一个问题](http://stackoverflow.com/a/26566362/1186208)中指出的那样,后续问题(和观察)是:这样的集合是什么让你超过函数组成? (具有不同“类别”的相同构造可能是另一回事......) – 2014-10-27 18:12:57

+0

我可以看到的一个潜在优势是可以从这种结构中提取组合函数,但对于简单的函数组合而言并非如此。一个人为的例子:“(+1)。 (-1)==(-1)。 (+1)'',但'[(+1),( - 1)]/= [(-1),(+ 1)]''(显然滥用符号)。 – 2014-10-27 19:03:34

+3

是的,我也注意到了。但你不能对他们做很多事情;除其他外,你无法从GADT之外预测它们的类型。 – 2014-10-27 19:06:40

3

上scrambledeggs'回答一个小小的改进,解决一些评论:

{-# LANGUAGE GADTs #-} 

import Data.Typeable 

data CascadingList i o where 
    Id :: CascadingList i i 
    Cascade :: Typeable b => (b -> o) -> CascadingList i b -> CascadingList i o 

现在,当你在Cascade模式匹配,你至少可以尝试和猜测哪些类型b是利用the eqT and cast functions from Data.Typeable,如果你猜对了,你实际上可以使用里面的函数。轻微的缺点是它只适用于具有Typeable实例(GHC至少可以导出)的类型。

5

使用DataKinds,可以公开的内部集合类型,这可能使使用组成部分容易的:

{-# LANGUAGE PolyKinds #-} 
{-# LANGUAGE TypeFamilies #-} 
{-# LANGUAGE KindSignatures #-} 
{-# LANGUAGE TypeOperators #-} 
{-# LANGUAGE DataKinds #-} 
{-# LANGUAGE GADTs #-} 
module Cascade where 
import Control.Monad ((>=>), liftM) 
import Control.Category ((>>>)) 

data Cascade (cs :: [*]) where 
    End :: Cascade '[a] 
    (:>>>) :: (a -> b) -> Cascade (b ': cs) -> Cascade (a ': b ': cs) 
infixr 5 :>>> 

-- a small example 
fs :: Cascade '[ String, Int, Float ] 
fs = read :>>> fromIntegral :>>> End 

-- alternate using functions from one chain then the other 
zigzag :: Cascade as -> Cascade as -> Cascade as 
zigzag End End = End 
zigzag (f :>>> fs) (_ :>>> gs) = f :>>> zigzag gs fs 

-- compose a chain into a single function 
compose :: Cascade (a ': as) -> a -> Last (a ': as) 
compose End = id 
compose (f :>>> fs) = f >>> compose fs 

-- generalizing Either to a union of multiple types 
data OneOf (cs :: [*]) where 
    Here :: a -> OneOf (a ': as) 
    There :: OneOf as -> OneOf (a ': as) 

-- start the cascade at any of its entry points 
fromOneOf :: Cascade cs -> OneOf cs -> Last cs 
fromOneOf fs (Here a) = compose fs a 
fromOneOf (_ :>>> fs) (There o) = fromOneOf fs o 

-- generalizing (,) to a product of multiple types 
data AllOf (cs :: [*]) where 
    None :: AllOf '[] 
    (:&) :: a -> AllOf as -> AllOf (a ': as) 
infixr 5 :& 

-- end the cascade at all of its exit points 
toAllOf :: Cascade (a ': as) -> a -> AllOf (a ': as) 
toAllOf End a  = a :& None 
toAllOf (f :>>> fs) a = a :& toAllOf fs (f a) 

-- start anywhere, and end everywhere after that 
fromOneOfToAllOf :: Cascade cs -> OneOf cs -> OneOf (Map AllOf (Tails cs)) 
fromOneOfToAllOf fs (Here a) = Here $ toAllOf fs a 
fromOneOfToAllOf (_ :>>> fs) (There o) = There $ fromOneOfToAllOf fs o 

-- type level list functions 
type family Map (f :: a -> b) (as :: [a]) where 
    Map f '[] = '[] 
    Map f (a ': as) = f a ': Map f as 

type family Last (as :: [*]) where 
    Last '[a] = a 
    Last (a ': as) = Last as 

type family Tails (as :: [a]) where 
    Tails '[] = '[ '[] ] 
    Tails (a ': as) = (a ': as) ': Tails as 

-- and you can do Monads too! 
data CascadeM (m :: * -> *) (cs :: [*]) where 
    EndM :: CascadeM m '[a] 
    (:>=>) :: (a -> m b) -> CascadeM m (b ': cs) -> CascadeM m (a ': b ': cs) 
infixr 5 :>=> 

composeM :: Monad m => CascadeM m (a ': as) -> a -> m (Last (a ': as)) 
composeM EndM = return 
composeM (f :>=> fs) = f >=> composeM fs 

fromOneOfM :: Monad m => CascadeM m cs -> OneOf cs -> m (Last cs) 
fromOneOfM fs (Here a) = composeM fs a 
fromOneOfM (_ :>=> fs) (There o) = fromOneOfM fs o 

-- end the cascade at all of its exit points 
toAllOfM :: Monad m => CascadeM m (a ': as) -> a -> m (AllOf (a ': as)) 
toAllOfM EndM a  = return $ a :& None 
toAllOfM (f :>=> fs) a = do 
    as <- toAllOfM fs =<< f a 
    return $ a :& as 

-- start anywhere, and end everywhere after that 
fromOneOfToAllOfM :: Monad m => CascadeM m cs -> OneOf cs -> m (OneOf (Map AllOf (Tails cs))) 
fromOneOfToAllOfM fs (Here a) = Here `liftM` toAllOfM fs a 
fromOneOfToAllOfM (_ :>=> fs) (There o) = There `liftM` fromOneOfToAllOfM fs o 
+0

我认为'Chain'也可以被实现为(封闭)类型的类型,因为类型参数'cs'明确指出将使用哪些构造函数。 – 2014-10-27 20:55:28

+0

Christian Conkle:是的,我做了这个[OneOf'](http://stackoverflow.com/questions/25414521/types-for-parser-combinators)。我现在在瞎搞。 – rampion 2014-10-27 20:59:15

+0

Christian Conkle:现在我放弃了封闭型家庭,因为当我试图做任何有趣的事情时,我总是感到内射型错误。 – rampion 2014-10-28 01:19:39