简体   繁体   English

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

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

I am an intermediate schemer, but only a haskell beginner. 我是中级计划者,但只有Haskell初学者。 Here is my problem: 这是我的问题:

Suppose you have an associative binary operation, says (>>=) . 假设您有一个关联的二进制运算,说(>>=) Is there a polyvariadic function p such that p (>>=) hgfe = h >>= g >>= f >>= e ? 是否有一个多元函数p使得p (>>=) hgfe = h >>= g >>= f >>= e

I am asking this question because this question says it is possible if the binary operation takes inputs of the same type. 我问这个问题是因为这个问题表明二进制运算是否可以接受相同类型的输入。 I wonder if this can be generalized. 我想知道这是否可以一概而论。

EDIT-1: I try to modify the code in http://okmij.org/ftp/Haskell/vararg-fn.lhs (the section of Variable number of variably typed arguments) with little progress. EDIT-1:我尝试修改http://okmij.org/ftp/Haskell/vararg-fn.lhs (可变类型自变量的可变数量部分)中的代码,但进展甚微。

EDIT-2: Simplify the code a bit. 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

Yes, you can create such a function. 是的,您可以创建这样的功能。 It is very ugly however, and you will need to explicitly type every argument you are going to pass to make the compiler find the correct instance. 但是,这非常丑陋,您将需要显式键入要传递的每个参数,以使编译器找到正确的实例。

Starting from the polyvariadic function template you linked, I arrived at 从您链接的多变量函数模板开始,我得出了

{-# 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

But you were asking whether we can do more generic, so that the binary operation is an argument as well. 但是您在问我们是否可以做更多的泛型运算,因此二进制运算也是一个参数。 Yes: 是:

{-# 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)

You can't (at least, not easily), because you need to know how many arguments you are getting ahead of time. 您不能(至少不容易),因为您需要提前知道要处理多少个参数。 Because all functions in Haskell are automatically curried, every function takes exactly one argument and returns one value. 因为Haskell中的所有函数都是自动管理的,所以每个函数都只接受一个参数并返回一个值。 Even a simple binary operator takes one argument (the first operand) and returns a function that takes one argument (the second operand) and returns a result. 甚至是简单的二进制运算符也可以接受一个参数(第一个操作数)并返回一个接受一个参数(第二个操作数)并返回结果的函数。 That is, 那是,

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

There is no way for your imaginary function p to know from its first argument how many other arguments are going to be given. 您的虚函数p无法从其第一个参数知道要给出多少个其他参数。 That is, what should the type of p be? 也就是说, 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?

Instead, the best you can do is use a fold, which takes an operation and a list of operands. 取而代之的是,您能做的最好的就是使用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

To see what I mean by "not easily", look at the implementation of printf in the Text.Printf module. 要了解“不容易”的含义,请查看Text.Printf模块中printf的实现。 Even that is not a good example, because the first argument carries information (the number of placeholders in the format string) that a binary operation alone does not. 即使这样也不是一个好例子,因为第一个参数携带的信息(格式字符串中占位符的数量)是仅二进制运算所不能提供的信息。

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

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