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

zca*_*ate 7 haskell scala clojure

我正在寻找在clojure和scala之间进行一些互操作.由于java本身现在有lambdas,我想到了数据之间的泛化以及如何将函数应用于集合

  • clojure函数扩展clojure.lang.IFn并概括了集合操作clojure.lang.ISeq
  • scala函数扩展scala.Function并概括了集合操作scala.collection.Traversable
  • java lambdas扩展java.util.function.Function和泛化集合操作java.util.stream.Stream

问题:

  • monads在这种情况下会有用吗?
  • 如果是这样,是否map可以跨所有集合类型实施操作,这可能是多么普遍?

例:

  (map (scala-fn +) 
       [1 2 3]
       (scala-seq [1 2 3]) 
       (.stream [1 2 3]))
  => (scala-seq [3 6 9])
Run Code Online (Sandbox Code Playgroud)

(添加haskell作为标签,以防人们可能知道的硬核类型)

Clojure,Scala和Java中的操作都采用集合,将函数应用于该集合并返回新集合.

  • 所有这些语言都在JVM上运行.
  • 但是,每种语言都定义了它自己的类来表示一个函数.

我对clojure比较熟悉,所以有以下操作:

 (into {} [[:a 1] [:b 2]]) => {:a 1 :b 2}
Run Code Online (Sandbox Code Playgroud)

这将clojure矢量转换为clojure地图.因为可以使用任何继承的数据结构的into操作.java.util.Listjava.util.List

我希望在clojure中使用一些scala库并面临某些障碍:

  • 与clojure一样,Scala也具有不可变数据结构,但它们的定义与clojure数据结构有很大不同
  • Scala函数继承自scala.Function,因此需要包装clojure.lang.IFn
  • Scala数据结构不继承,java.util.List这意味着:

    (into {} (scala-list [:a 1] [:b 2])) 不管用.

  • 我正在寻找重新实现一些基本的clojure函数,这些函数也包含scala数据结构.(map,reduce,mapcat等......)

功能看起来像:

 (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]
Run Code Online (Sandbox Code Playgroud)
  • 我正在寻找的是能够在收集操作中使用clojure和scala函数.
  • 我可以在不使用monads的情况下执行此操作(通过检查集合和函数类型并在函数应用程序之前执行一些强制执行)
  • 我在这里问的问题对我来说有点好奇,因为我在monad上读到的所有文献似乎都认为任何函数f:X->Y都是通用的.
  • 但是,在clojure/scala/lambda interop的情况下,clojure函数,scala函数和java lambda不是通用的.我很好奇类别理论如何用来解决这个问题.

yok*_*kto 1

我只能给你 Haskell 答案,因为我不会说任何其他语言。然而对我来说,您似乎主要是在寻找一种将输入自动转换为函数的方法。它似乎与 monad 没有任何关系。

(concat (scala-list 1 2) [3 4]) => (scala-list 1 2 3 4)
Run Code Online (Sandbox Code Playgroud)

如果我将其翻译为 Haskell,我会给它一个这样的类型

concat :: (IsList l1, IsList l2) => l1 elem -> l2 elem -> [elem]
Run Code Online (Sandbox Code Playgroud)

其中 ToList 是一个类型类,它只会将此容器转换为列表

class IsListOf a where
    toList :: a elem -> [elem]
Run Code Online (Sandbox Code Playgroud)

从您的示例中尚不清楚您将如何决定输出类型,因此我无法提供帮助。

(map + [1 2] (scala-list 3 4)) => [4 6]
Run Code Online (Sandbox Code Playgroud)

在 Haskell 中,这个函数不称为 map,而是 zipWith。如果你想自动转换输入,你可以这样做。

zipWith :: (IsList l1, IsList l2) => (a -> b -> c) -> l1 a -> l2 b -> [c]
Run Code Online (Sandbox Code Playgroud)

如果你想自动转换函数,你也可以这样做。

zipWith :: (IsList l1, IsList l2, Is2Function f) => f a b c -> l1 a -> l2 b -> [c]
Run Code Online (Sandbox Code Playgroud)

Is2Function 又将是一个仅转换为二元函数的类型类

class Is2Function f where
    toFunction :: f a b c -> a -> b -> c
Run Code Online (Sandbox Code Playgroud)

关于概括,还有一些事情需要牢记。我在前面说过,我不知道你会如何决定输出。当你进行许多泛化时,编译器有时也会遇到这个问题(至少在 haskell 中)。概括从表面上看似乎很好,但它们并不总是能让事情变得更清晰,并且可能会导致歧义。