简体   繁体   English

如果函数可以是不同类型,monadic规则将如何应用

[英]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 functions extend clojure.lang.IFn and generalises collection operations on clojure.lang.ISeq clojure函数扩展clojure.lang.IFn并在clojure.lang.ISeq上推广集合操作
  • 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上推广集合操作

Questions: 问题:

  • Would monads be useful in this case? monads在这种情况下会有用吗?
  • If so, would a 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中的操作都采用集合,将函数应用于该集合并返回新集合。

  • All of these languages run on the JVM. 所有这些语言都在JVM上运行。
  • However, each language defines it's own class to represent a function. 但是,每种语言都定义了它自己的类来表示一个函数。

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, like clojure also has immutable data structures, but they are defined very differently from clojure data structures 与clojure一样,Scala也具有不可变数据结构,但它们的定义与clojure数据结构有很大不同
  • Scala functions inherit from 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]
  • What I'm looking for is the ability to use both clojure and scala functions in collection operations. 我正在寻找的是能够在收集操作中使用clojure和scala函数。
  • I can do this without using monads (by checking the collection and function types and doing some coercing before function application) 我可以在不使用monads的情况下执行此操作(通过检查集合和函数类型并在函数应用程序之前执行一些强制执行)
  • What I'm asking here serves as a bit of a curiosity for me, as all the literature I've read on monads seem to presume that any function f:X->Y is universal. 我在这里问的问题对我来说有点好奇,因为我在monad上读到的所有文献似乎都假设任何函数f:X->Y都是通用的。
  • However, in the case of clojure/scala/lambda interop, a clojure function, a scala function and a java lambda are not universal. 但是,在clojure / scala / lambda interop的情况下,clojure函数,scala函数和java lambda不是通用的。 I'm curious about how category theory might be used to solve this problem. 我很好奇类别理论如何用来解决这个问题。

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.

相关问题 如何在 Scala 中通过“andThen”组合 Function1 类型的单子函数/方法? - How to compose monadic functions/methods of type Function1 via 'andThen' in Scala? 单子收集,单子类型和单子手术之间有什么区别? - what is difference between monadic collection, monadic type and monadic operation? 如何一般地组合返回不同单子的单子函数? - How to generically compose monadic functions that return different monads? 如何实现一元解析? - How to implement monadic parsing? 如何在 Scala 中进行单子日志记录 - How to Monadic Logging in Scala 如何为类型R [Out] {type In}实现monadic接口(map,flatMap)? - How can I implement a monadic interface (map, flatMap) for a type R[Out] { type In }? 接受两个monadic值并返回单个monadic值的通用函数 - Generic function that accepts two monadic values and returns a single monadic value 如何使用 Scala Guice 绑定使用 monadic 类型参数扩展 Trait 的类? - How to bind a class that extends a Trait with a monadic type parameter using Scala Guice? 如何创建将包裹其他子类型“ I”的子类型“ I”? - How could I create a sub type of `I` that would wrap other sub types of `I`? 如何将 Scala Function 应用于两个不同的列数据框 Scala - How to apply a Scala Function to two different columns data frame Scala
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM