繁体   English   中英

haskell-用关联的二进制运算链接元素

[英]haskell - chain up elements with an associative binary operation

我是中级计划者,但只有Haskell初学者。 这是我的问题:

假设您有一个关联的二进制运算,说(>>=) 是否有一个多元函数p使得p (>>=) hgfe = h >>= g >>= f >>= e

我问这个问题是因为这个问题表明二进制运算是否可以接受相同类型的输入。 我想知道这是否可以一概而论。

EDIT-1:我尝试修改http://okmij.org/ftp/Haskell/vararg-fn.lhs (可变类型自变量的可变数量部分)中的代码,但进展甚微。

EDIT-2:稍微简化代码。

{-# LANGUAGE FunctionalDependencies, FlexibleInstances #-}


module Main where


class Lfold f a b | b -> a where 
  lfold :: (a -> (f a) -> (f a)) -> (f a) -> a -> b

instance Lfold f a (f a) where
  lfold op rid x = op x rid

instance Lfold f a b => Lfold f a (a -> b) where
  lfold op rid x y = lfold op (op x rid) y


test :: [String]
test = lfold (:) [] "a" "b" "c"

main :: IO ()
main = putStrLn $ show test

是的,您可以创建这样的功能。 但是,这非常丑陋,您将需要显式键入要传递的每个参数,以使编译器找到正确的实例。

从您链接的多变量函数模板开始,我得出了

{-# LANGUAGE FlexibleInstances, InstanceSigs, MultiParamTypeClasses #-}

class ImplicitChain m a r where
  p :: m a -> r

instance Monad m => ImplicitChain m a (m a) where
  p :: m a -> m a
  p x = x

instance (Monad m, ImplicitChain m b r) => ImplicitChain m a ((a -> m b) -> r) where
  p :: m a -> (a -> m b) -> r
  p x f = p (x >>= f)


h :: Int -> [Int]
h = replicate 2
g :: Int -> [Int]
g = (:[])
f :: Int -> [Int]
f = flip enumFromTo 2

test :: [Int]
test = p [1::Int] h g f

但是您在问我们是否可以做更多的泛型运算,因此二进制运算也是一个参数。 是:

{-# LANGUAGE FlexibleInstances, InstanceSigs, MultiParamTypeClasses, UndecidableInstances #-}

class ImplicitVariadic a b r where
  p :: (a -> b -> a) -> r

instance ImplicitVariadic a b (a -> a) where
  p :: (a -> b -> a) -> a -> a
  p _ x = x

instance (ImplicitVariadic a b (a -> r)) => ImplicitVariadic a b (a -> b -> r) where
  p :: (a -> b -> a) -> a -> b -> r
  p f x y = p f (f x y)

您不能(至少不容易),因为您需要提前知道要处理多少个参数。 因为Haskell中的所有函数都是自动管理的,所以每个函数都只接受一个参数并返回一个值。 甚至是简单的二进制运算符也可以接受一个参数(第一个操作数)并返回一个接受一个参数(第二个操作数)并返回结果的函数。 那是,

a + b == (+) a b
      == ((+) a) b

您的虚函数p无法从其第一个参数知道要给出多少个其他参数。 也就是说, p的类型应该是什么?

p :: (a -> a -> a) -> a                -- zero arguments?
p :: (a -> a -> a) -> a -> a           -- one argument?
p :: (a -> a -> a) -> a -> a -> a      -- two arguments?
p :: (a -> a -> a) -> a -> a -> a -> a -- three arguments?

取而代之的是,您能做的最好的就是使用fold,它需要一个操作和一个操作数列表

foldr (+) 0 [h, g, f, e] == h + g + f + e + 0  -- explicit first argument of 0
foldr1 (+) [h, g, f, e] == h + g + f + e -- assumes a list of at least one value

要了解“不容易”的含义,请查看Text.Printf模块中printf的实现。 即使这样也不是一个好例子,因为第一个参数携带的信息(格式字符串中占位符的数量)是仅二进制运算所不能提供的信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM