[英]how would monadic rules apply if the function could be of a different type
I'm looking at doing some interop between clojure and scala. 我正在寻找在clojure和scala之间进行一些互操作。 As java itself now has lambdas, I was thinking of a generalisation between data and how to apply a function to a collection 由于java本身现在有lambdas,我想到了数据之间的泛化以及如何将函数应用于集合
clojure.lang.IFn
and generalises collection operations on clojure.lang.ISeq
clojure函数扩展clojure.lang.IFn
并在clojure.lang.ISeq
上推广集合操作 scala.Function
and generalises collection operations on scala.collection.Traversable
scala函数扩展scala.Function
并在scala.collection.Traversable
上泛化集合操作 java.util.function.Function
and generalises collection operations on java.util.stream.Stream
java lambdas扩展java.util.function.Function
并在java.util.stream.Stream
上推广集合操作 Questions: 问题:
map
operation be implemented across all collection types and how might this be generalisable? 如果是这样,是否可以跨所有集合类型实现map
操作,这可能是如何通用的? Example: 例:
(map (scala-fn +)
[1 2 3]
(scala-seq [1 2 3])
(.stream [1 2 3]))
=> (scala-seq [3 6 9])
Continued (added haskell as a tag just in case the hardcore type people might know) 续 (添加haskell作为标签,以防人们可能知道的硬核类型)
There are operations in both Clojure, Scala and Java that take a collection, applies a function to that collection and returns a new collection. Clojure,Scala和Java中的操作都采用集合,将函数应用于该集合并返回新集合。
I'm more familiar with clojure, so there are operations like: 我对clojure比较熟悉,所以有以下操作:
(into {} [[:a 1] [:b 2]]) => {:a 1 :b 2}
Which converts a clojure vector into a clojure map. 这将clojure矢量转换为clojure地图。 Because the into
operation generalises on java.util.List
any datastructure that inherits java.util.List
can be used. 因为into
操作在java.util.List
说明,所以可以使用任何继承java.util.List
结构。
I wish to work with some scala libraries in clojure and face certain obstacles: 我希望在clojure中使用一些scala库并面临某些障碍:
scala.Function
and so need to be wrapped to clojure.lang.IFn
Scala函数继承自scala.Function
,因此需要包装到clojure.lang.IFn
Scala datastructures do not inherit from java.util.List
which means that: Scala数据结构不从java.util.List
继承,这意味着:
(into {} (scala-list [:a 1] [:b 2]))
will not work. (into {} (scala-list [:a 1] [:b 2]))
将不起作用。
I'm looking to reimplement some basic clojure functions that also incorporate scala datastructures. 我正在寻找重新实现一些基本的clojure函数,这些函数也包含scala数据结构。 (map, reduce, mapcat, etc...) (map,reduce,mapcat等......)
The functionality would look something like: 功能看起来像:
(into {} (scala-list [:a 1] [:b 2])) => {:a 1 :b 2}
(into (scala-map) [[:a 1] [:b 2]]) => (scala-map :a 1 :b 2)
(concat (scala-list 1 2) [3 4]) => (scala-list 1 2 3 4)
(concat [1 2] (scala-list 3 4)) => (1 2 3 4) ;lazy seq
(map + [1 2] (scala-list 3 4)) => [4 6]
(map (scala-fn +) [1 2] (scala-list 3 4)) => [4 6]
f:X->Y
is universal. 我在这里问的问题对我来说有点好奇,因为我在monad上读到的所有文献似乎都假设任何函数f:X->Y
都是通用的。 scala functions extend scala.Function and generalises collection operations on scala.collection.Traversable scala函数扩展scala.Function并在scala.collection.Traversable上泛化集合操作
java lambdas extend java.util.function.Function and generalises collection operations on java.util.stream.Stream java lambdas扩展java.util.function.Function并在java.util.stream.Stream上推广集合操作
First, the good news: this isn't correct, Java and Scala lambdas can implement any SAM (single abstract method) interface. 首先,好消息:这是不正确的,Java和Scala lambdas可以实现任何SAM(单一抽象方法)接口。 This allows using Java lambdas with APIs expecting scala.FunctionN
and Scala lambdas with APIs expecting java.util.function.*
(including Java streams). 这允许将Java lambdas与期望scala.FunctionN
和Scala lambdas的API一起使用期望java.util.function.*
(包括Java流)的API。 This interoperability should be complete in Scala 2.12 and later (so far as I know). 这种互操作性应该在Scala 2.12及更高版本中完成(据我所知)。
The bad news (you knew this was coming): when talking about Scala collection API specifically, it also very much relies on implicit parameters, and those aren't really usable from Java or Clojure. 坏消息(你知道这会发生):在专门讨论Scala集合API时,它也非常依赖于隐式参数,而这些参数在Java或Clojure中并不真正可用。 Similarly, Clojure collection API relies on dynamic typing, and IFn
isn't a SAM type (because it covers functions with different numbers of arguments). 类似地,Clojure集合API依赖于动态类型,而IFn
不是SAM类型(因为它涵盖具有不同数量的参数的函数)。 And of course, for use from Clojure, interoperation between Java and Scala lambdas doesn't help. 当然,对于Clojure的使用,Java和Scala lambdas之间的互操作并没有帮助。
More generally speaking, the 3 collection APIs (4 if you count the redesing coming in Scala 2.13) are probably too different to be unified like that. 更一般地说,3个集合API(如果计算Scala 2.13中的redesing,则为4个)可能太不同了,不能像这样统一。
I don't see any way in which monads per se would be useful here. 我没有看到任何方式monad本身在这里有用。 If I was trying to do something usable from Clojure, I'd go with "checking the collection and function types and doing some coercing before function application" as the solution. 如果我试图在Clojure中做一些可用的事情,我会选择“检查集合和函数类型并在函数应用程序之前做一些强制”作为解决方案。 Protocols could simplify it, but with some performance cost. 协议可以简化它,但需要一些性能成本。
I can only give you the Haskell answer, since I don't speak any of those other languages. 我只能给你Haskell的答案,因为我不会说任何其他语言。 However to me it seems like you're mostly looking for a way to automatically convert the input to a function. 但对我来说,似乎你主要是在寻找一种自动将输入转换为函数的方法。 It doesn't appear to have anything to do with monads. 它似乎与monads没有任何关系。
(concat (scala-list 1 2) [3 4]) => (scala-list 1 2 3 4)
If I translate this to Haskell I would give it a type like this 如果我把它翻译成Haskell,我会给它一个这样的类型
concat :: (IsList l1, IsList l2) => l1 elem -> l2 elem -> [elem]
where ToList is a typeclass which will just convert this container to a list 其中ToList是一个类型类,它只是将此容器转换为列表
class IsListOf a where
toList :: a elem -> [elem]
It is not clear from your example how you would decide on an output type, so I can't help with that. 从你的例子中不清楚你将如何决定输出类型,所以我无能为力。
(map + [1 2] (scala-list 3 4)) => [4 6]
In Haskell this function is not called map but zipWith. 在Haskell中,这个函数不是map而是zipWith。 If you want to automcatically convert the input you can do it like this. 如果你想自动转换输入,你可以这样做。
zipWith :: (IsList l1, IsList l2) => (a -> b -> c) -> l1 a -> l2 b -> [c]
If you want to automatically convert the function you can do it just as well. 如果你想自动转换功能,你也可以这样做。
zipWith :: (IsList l1, IsList l2, Is2Function f) => f a b c -> l1 a -> l2 b -> [c]
Is2Function would again be a typeclass that just converts to a 2-ary function Is2Function将再次成为仅转换为2-ary函数的类型类
class Is2Function f where
toFunction :: f a b c -> a -> b -> c
There is also something to keep in mind concerning generalizations. 关于概括,还有一些要记住的事项。 I said in the previous that I didn't know how you would decide on the output. 我之前说过,我不知道你将如何决定输出。 This is a problem the compiler also has from time to time (at least in haskell) when you do to many generalizations. 当你做许多概括时,这是编译器也经常遇到的问题(至少在haskell中)。 Generalizations seem nice on the surface but they don't always make things more clear and can lead to ambiguity. 概括表面看起来不错,但它们并不总是使事情更加清晰,并且可能导致歧义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.