`String.prototype.substr` を PureScript で実装するにはどうすれば良いですか？

  * <https://github.com/purescript/purescript-strings/pull/116>
  * <https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/substr>
CC BY-SA 4.0
2019-04-17T02:27:07.807
54232
2019-04-17T02:27:07.807
2341
question
purescript
String.prototype.substr を PureScript で実装するにはどうすれば良いですか？
strings パッケージの `slice` や `drop` を使うことで実現できます。

↓は実装例です。

`Data.String` (`Data.String.CodePoints`) モジュールではなく `Data.String.CodeUnits`
モジュールを使っているのは JavaScript の String に近づけるためです。

```

    module Main
      ( main
      ) where
    
    import Prelude
    
    import Data.Maybe as Maybe
    import Data.String.CodeUnits as CodeUnits
    import Effect (Effect)
    import Test.Unit as TestUnit
    import Test.Unit.Assert as Assert
    import Test.Unit.Main as TestUnitMain
    
    substr :: Int -> Int -> String -> String
    substr start length s
      | length <= 0 = ""
      | otherwise =
        let start' = max 0 (start + (if start < 0 then CodeUnits.length s else 0))
        in Maybe.fromMaybe "" (CodeUnits.slice start' (start' + length) s)
    
    substr' :: Int -> String -> String
    substr' start s =
      let start' = max 0 (start + (if start < 0 then CodeUnits.length s else 0))
      in CodeUnits.drop start' s
    
    main :: Effect Unit
    main = TestUnitMain.runTest do
      TestUnit.test "substr" do
        let str = "Mozilla"
        Assert.equal "oz" (substr 1 2 str)
        Assert.equal "zilla" (substr' 2 str)
        let aString = "Mozilla"
        Assert.equal "M" (substr 0 1 aString)
        Assert.equal "" (substr 1 0 aString)
        Assert.equal "a" (substr (-1) 1 aString)
        Assert.equal "" (substr 1 (-1) aString)
        Assert.equal "lla" (substr' (-3) aString)
        Assert.equal "ozilla" (substr' 1 aString)
        Assert.equal "Mo" (substr (-20) 2 aString)
        Assert.equal "" (substr 20 2 aString)
    
    
```

`start` や `length` に負の数を使わない場合はもうすこしすっきりと書けます。

```

    substr :: Int -> Int -> String -> String
    substr start length s =
      Maybe.fromMaybe "" (CodeUnits.slice start (start + length) s)
    
    substr' :: Int -> String -> String
    substr' = CodeUnits.drop
    
```

* * *

質問とは関係ないですが、 JavaScript でも `substr` ではなく `substring` を使うほうが良いかもしれません。
<https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/substr>
CC BY-SA 4.0
2019-04-17T02:27:07.807
54233
2019-04-17T02:27:07.807
2341
54232
answer