用字符串映射行为

map behaviour with strings

假设 map 是:

map :: (a -> b) -> [a] -> [b]

为什么 R.map(R.toUpper, 'hello') returns ['H', 'E', 'L', 'L', 'O'] 而不是 "HELLO"

在 haskell 中,例如,字符串是一个字符列表,因此 map toUpper "hello" 的行为符合预期 (HELLO)。

Ramda 的 map 不应该做同样的事情吗?


这可能是一种设计选择,但我认为 Ramda 的映射可能违反了函子定律: 如果我们将 id 函数映射到一个仿函数上,我们不会取回原始仿函数

console.log(
  R.map(R.identity, 'Hello World'),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>

为什么我不希望 map 表现得更像:

const map = (fn, string) => string.replace(/./g, fn);


console.log(
  map(R.toUpper, 'hello world'),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>

正如评论所说,字符串不是 functors。函子法则要求

map :: Functor f => (a -> b) -> f a -> f b

也就是说,对于一个包含一个或多个类型 a 的函子和一个从类型 a 到类型 b 的函数,它将 return 一个函子拥有一个或多个 b 类型的物品。 String 不能这样做,因为它只包含字符。例如,您期望 map(_ => 1.234, "hello") 到 return 是什么?

Ramda 对字符串的行为不是故意的。正如 Bergi 所建议的那样,它只是脱离了实施。字符串看起来很像数组(具有整数 length 属性和整数索引子元素),代码将它们视为数组。

Ramda 一直打算做一个底层库,创始人对编写手持代码并不是特别感兴趣。如果您提供所需的类型,它应该像宣传的那样工作,但如果您不提供,则几乎没有任何保证。但是,如果您对此有强烈的感觉,请随意 raise an issue with the Ramda team about it, or even better, raise a pull request 采取您喜欢的行为。它可能不会被接受,但它会得到公平的听证会。