Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • 04:00

    xuwei-k on sbt-pgp-2.0.2

    (compare)

  • 04:00

    xuwei-k on master

    Update sbt-pgp to 2.0.2 (compare)

  • 04:00
    xuwei-k closed #157
  • 03:18
    nscala-time-bot[bot] review_requested #157
  • 03:18
    nscala-time-bot[bot] opened #157
  • 03:18

    nscala-time-bot[bot] on sbt-pgp-2.0.2

    Update sbt-pgp to 2.0.2 (compare)

  • Nov 28 16:32

    xuwei-k on Scala-3.0.0-M2

    (compare)

  • Nov 28 16:30

    xuwei-k on master

    add Scala 3.0.0-M2 (compare)

  • Nov 28 16:21

    xuwei-k on Scala-3.0.0-M2

    add Scala 3.0.0-M2 (compare)

  • Nov 23 19:51

    xuwei-k on sbt-1.4.4

    (compare)

  • Nov 23 19:51

    xuwei-k on master

    Update sbt to 1.4.4 (compare)

  • Nov 23 19:51
    xuwei-k closed #156
  • Nov 23 16:54
    nscala-time-bot[bot] review_requested #156
  • Nov 23 16:54
    nscala-time-bot[bot] opened #156
  • Nov 23 16:53

    nscala-time-bot[bot] on sbt-1.4.4

    Update sbt to 1.4.4 (compare)

  • Nov 23 16:52

    xuwei-k on master

    Update scala-steward.yml (compare)

  • Nov 19 22:20

    xuwei-k on master

    Update scala-steward.yml (compare)

  • Nov 19 15:27

    xuwei-k on master

    Scala 2.13.4 (compare)

  • Nov 19 03:57

    xuwei-k on master

    timeout-minutes: 10 (compare)

  • Nov 18 17:04

    xuwei-k on github_actions

    (compare)

Ryuhei Ishibashi
@rysh
あるい.toResult.map(...)
Ryuhei Ishibashi
@rysh
Teratailにコミュニティ機能できてました。Haskellが登録されてるので気になりますが、どんな意味があるんでしょうね。
https://teratail.com/communities
なめらかな関数
@devilune_twitter
初めまして。質問させてください。
見よう見まねでファンクターおよびそのListインスタンスを自作したのですが、下記コードのrun[List, Int, Int](List(1, 2, 3), a => a * 3)という部分で型パラメータ指定を取り除けず悩んでおります。
いちいち指定しないでもList(1, 2, 3)から推論して欲しいと思ったのですが、これは仕方がないのでしょうか?それとも何か実装がおかしいのでしょうか?
(ファンクター云々以前にScalaの基本的な知識不足かなと思ってます...)
object Main {

  trait Functor[F[_]] {
    def fmap[A, B](fa: F[A])(f: A => B): F[B]
  }

  object Functor {

    implicit object ListFunctor extends Functor[List] {
      override def fmap[A, B](fa: List[A])(f: A => B): List[B] = fa.map(f)
    }

  }

  def run[F[_], A, B](fa: F[A], mapping: A => B)(implicit f: Functor[F]): Unit = {
    val result = f.fmap[A, B](fa)(mapping)
    print(result)
  }

  def main(args: Array[String]): Unit = {
    // ここの型パラメータ指定([List, Int, Int])をやめたいが、取り除くとaがNothingと推論されてしまい
    // "Cannot resolve symbol *"というコンパイルエラーになる
    run[List, Int, Int](List(1, 2, 3), a => a * 3)
  }

}
kazchimo
@kazchimo
@devilune_twitter run関数をカリー化すれば推論が通るようになると思います
https://qiita.com/t-yng/items/1fe622911bdd379d37ea  この記事が参考になるかと
なめらかな関数
@devilune_twitter

@kazchimo おおおできました!
カリー化するという発想はなかったです...。
記事も参考になりました。
ありがとうございます!

誰かの参考になることもあるかと思うので修正後のコードを載せておきます。

  def run[F[_], A, B](fa: F[A])(mapping: A => B)(implicit f: Functor[F]): Unit = {
    val result = f.fmap[A, B](fa)(mapping)
    print(result)
  }

  def main(args: Array[String]): Unit = {
    run(List(1, 2, 3))(a => a * 3)
  }
basashi
@basashi_code_twitter
今日はじめて文法を勉強したのですがsetterを定義するときに使う_=がどうしても受け付けません。イコールも多くて読みにくいと感じます。仕様を変更するという議論はないのでしょうか?
seraph
@seraphr

そういう議論は(どこかであるのかもしれませんが)、私は把握していません。

そもそも、_=って殆ど使わないです。
Scala使い始めて8年以上経ってると思いますが、多分数回しか使ったことがないです。

  • 殆どの場合、immutableにするのでsetterを定義しない
  • そして、数少ないsetterを定義する場合も、varで定義すれば良い

ので、必要になる場面がめちゃくちゃ限られてるんですよね。
なので、読みにくさとか書きにくさを感じること自体が無いです。

basashi
@basashi_code_twitter
確かに、基本immutableだったらsetter自体使うのがまれですね。ありがとうございました。
kenji yoshida
@xuwei-k
そういえばそんな文法あったなぁ(数年使ってないし最近見た覚えない)っていうくらい全く使わないですね
代入っぽく書けるだけなので、機能的にそれ以外にすごいこと出来るわけでもないので、あれに違和感あるけどsetterっぽい何か定義したくなったら def setFoo(foo: Foo): Unitと普通のメソッド定義というのでも
basashi
@basashi_code_twitter
その後わかったのですが、Scalaでは2+12.+(1)は同じことを意味するのですね。イコールをメソッド名に含めるというなんとも不思議な構文の意味がわかりました。皆さんありがとうございました。
basashi
@basashi_code_twitter
Scalaを勉強していてメソッドと関数の違いに度々悩まされます。apply()を持つオブジェクトかどうかというような、違いについては理解できたのですが、なぜ同じような機能を持つものが別のものとして定義されているのかわかりません。何か利点があるのでしょうか?
seraph
@seraphr
一応違いとしては以下のような感じですね
  • 関数は
    • (狭義には)FunctionN型のインスタンスです
    • オブジェクトなので変数に代入して持ち運べます
    • (scala2では)型引数を受け取るような関数オブジェクトは作れません
  • メソッドは
    • defで定義されたものです
    • オブジェクトではないので変数に代入できません
      • 関数に変換すればできますが、それはすでにメソッドではありません
    • 型引数を持つメソッドを定義することができます
    • JVMのメソッドと1:1対応します(ので、関数より色々コストが安いはず)
kazchimo
@kazchimo

メソッド:
クラスやオブジェクト、トレイトなどのメンバとしての関数。
defというキーワードが割り当てられている。
関数:
値としてのただの関数。もちろんクラスなどのメンバにもなりうる。

が簡単に言えばそれぞれの特徴かと思います。
なぜ被りがあるかというと厳密に言うと両者には違いがあるからです。
関数はScalaでいう第一級の値、メソッドは第一級の値ではないというのが大まかな説明になります。

まあ関数のほうが値として色々柔軟に扱えるので扱いやすい、ただメソッドのほうがオブジェクト指向的な観点で見たときにクラスのインターフェースっぽいくらいの理解でいい気がします。

参考: https://hexx.github.io/scala_text/function.html

kenji yoshida
@xuwei-k
https://scala-text.github.io/scala_text/function.html fork先が検索によく引っかかるんですが、それこっちが公式なので :pray:
kazchimo
@kazchimo
あ、ども訂正ありがとうございます🙇🏼‍♂️
basashi
@basashi_code_twitter
関数がメソッドの上位互換のように見えてしまい、関数だけでいいのではとなって、ムズムズします。
あ、もしかして、あまり深く考えなくても大丈夫な領域ですか?
kenji yoshida
@xuwei-k
疑問に思うのはある意味普通かも(?)
そのあたりは、Javaとの互換や、JVMの都合などもあって、まぁ考えたらおもしろいかもしれないけど、入門時にそんなに深く考えなくてもそれなりに先にすすめるので、
深く考えなくても、考えたかったら考えてもどっちでも(?)
basashi
@basashi_code_twitter
序盤でつまずくのも何なんで、とりあえず横においておくことにしました笑。お付き合いいただきありがとうございました。
basashi
@basashi_code_twitter
質問を連投して申し訳ございません。コンパニオンオブジェクトというもの勉強したのですが、classと同じ名前にするようです。別のものと同じ名前をつけると、どっちをのことを指しているのかわからなくなる気がするのですがどうなんでしょうか?
kenji yoshida
@xuwei-k
初心者にとってはややこしいんですけど、classとobjectは、命名に関わるのが、型としての名前空間と、値としての名前空間で意味違うので、原理上(コンパイラやScalaに慣れた人にとっては)判断不可能になることは無いですね
basashi
@basashi_code_twitter
2つの名前空間が干渉せずに別々に存在するということですね。なるほど、ありがとうございます。このへんの細かいことはドキュメンテーションのどこを見れば勉強できるのでしょうか?
kazchimo
@kazchimo

んーどこかを読めば完璧に理解できるというより、いろんなドキュメントやソースコード読んで型や値についての理解を深めたらわかるという感じかなと思います。
この話題に限って言えば以下の感じですね。

例えば

class Dog
object Dog

という定義があったとして、

Dogクラス:
型=Dog
値=インスタンス(new Dogされたもの)

コンパニオンオブジェクト:
型=Dog.type
値=Dogオブジェクト自身

という対応になります。
objectは型の定義ではなく値の定義に近いです。
じゃあ.typeは何かというとこれはシングルトン型と言われるもので、これは一応コップ本に軽くですが記載があります
ここらへんは僕も入門のときに戸惑った記憶があります

seraph
@seraphr

言語仕様的にはこのあたりですね

https://scala-lang.org/files/archive/spec/2.13/02-identifiers-names-and-scopes.html
There are two different name spaces, one for types and one for terms. The same name may designate a type and a term, depending on the context where the name is used.

basashi
@basashi_code_twitter
確かに落ち着いて考えればobjectというキーワードが付くので、objectは型の定義ではないことは感じ取れますね
basashi
@basashi_code_twitter
==equalsに置き換えられるのでしょうか?equalsは同値性を調べるそうですが、
scala> class A
class A

scala> val a = new A
val a: A = A@3503cb9c

scala> val b = new A
val b: A = A@6a601152

scala> a == b
val res2: Boolean = false
こちらはなぜfalseになるのでしょうか
equalsが宣言されていないときはjava.lang.Object#equalsが呼ばれるのでしょうか?これはeqと同じですか?
seraph
@seraphr

参照型の==equalsの呼び出しになります。

equalsが宣言されていないときはjava.lang.Object#equalsが呼ばれるのでしょうか?これはeqと同じですか?

はい、その通りです。
参照型のデフォルトの実装は、同じインスタンスであるかどうかをチェックします。

basashi
@basashi_code_twitter
迅速な回答ありがとうございます。助かりました
basashi
@basashi_code_twitter
パターンマッチングで無視したいところにアンダースコアを使うのは慣例でしょうか?それともアンダースコアであると特別な機能があるのでしょうか?
seraph
@seraphr

意味があります。
https://scala-lang.org/files/archive/spec/2.13/08-pattern-matching.html#variable-patterns

_ によるパターンマッチは、変数パターンの一種です。
普通の変数パターンだと、同じ変数を一つのパターン内に複数回登場させることはできません。

scala> (1, 2) match {case (a, a) => println(a)}
                              ^
       error: a is already defined as value a

_でマッチさせると、マッチした値を後から参照することが出来ませんが、複数回登場させることが出来ます。

scala> (1, 2) match {case (_, _) => println("マッチ")}
マッチ
basashi
@basashi_code_twitter
なるほど、理解しました。コードまで示してくださってありがとうございます
basashi
@basashi_code_twitter
連投申し訳ないです。多分今日はこれで最後です笑
trait Shape {
  def sides: Int
  def perimeter: Double
  def area: Double
}

sealed trait Rectangular extends Shape {
  def width: Double
  def height: Double
  val sides = 4
  override val perimeter = 2*width + 2*height
  override val area = width*height
}
overrideをつけるか、つけないかが混在しているように見えます。(sidesはつけていないがareaはつけている)つける・つけないの区別は有るのでしょうか?
seraph
@seraphr

super typeで実装が無いval や def を実装する場合、overrideはつけてもつけなくても良いです。
super typeで実装が有るval や def を実装する場合、つけないといけません。
super typeに定義が無いvalやdefでoverrideをつけるとコンパイルエラーになります。

上記から、私は、実装の有無に関係なく、overrideをつけるようにしています(名前とかシグネチャとかをミスったり変わったりしたときにコンパイルエラーになってくれるので)


overrideにはstackable trait patternで利用するabstract overrideというのもありますが、とりあえず考えなくて良いと思います。

basashi
@basashi_code_twitter
読んでいても実装しているのがわかるので習慣的につけたいと思います。ありがとうございました。
basashi
@basashi_code_twitter
コードをbotに投げるのに苦戦してしまい、荒らしてしまいました。ごめんなさい。
import scala.annotation.tailrec
sealed trait IntList{

  def double:IntList = {

    @tailrec
    def loop(list:IntList, result:IntList):IntList =
      list match {
        case End => result
        case Pair(head, tail) => loop(tail, Pair(head*2, result))
      }
    loop(this, End)
  }
}

case object End extends IntList
final case class Pair(head: Int, tail: IntList) extends IntList

object Main {
  def main(args: Array[String]): Unit = {
    val example = Pair(1, Pair(2, Pair(3, End)))
    println(example.double)  
  }
}
Pair(6,Pair(4,Pair(2,End)))
という結果になってしまい、並び順が逆になってしまうのですが、これはheadを変化させない再帰関数をもう一度適用して、逆を逆で打ち消すしかないのでしょうか?もう少しスマートな解決策はありますか?末尾再帰にそこまでこだわらくても良いのでしょうか?
seraph
@seraphr
末尾再帰にすると、foldLeft的に処理するしか無いので、reverseするしか無い気がしますね。
scalaの標準ライブラリだと、一度mutableなデータ構造で(call stackを使わずに)データを作ってから、目的のimmutableなデータ構造に変換してたと思います
basashi
@basashi_code_twitter
そうなっちゃいますよね。ありがとうございました。Scalaでは何でもかんでも頑張ってでも末尾再帰にしたほうが良いのでしょうか?ケース・バイ・ケースですか?
seraph
@seraphr

私は癖で、書けるときは末尾再帰にしちゃいますけど、ほとんどのデータ構造・状況では素直な再帰で書いても問題起こらないんじゃないですかね?
Arrayとかにアクセスするループとかを再帰関数に変換するとか、Linked Listみたいな一直線な再帰構造に対する処理を再帰的に書くとかすると、末尾再帰にしないとstack overflow errorに成りうるので気にしたほうが良いですが、ほとんどの場合は標準ライブラリとかで定義されているコンビネータ使えば済むので。

極端な話、末尾再帰にするのが難しい(めっちゃ読みにくくなる)ループするアルゴリズムというのは存在していて、そういうのを無理に書くよりは、そのままwhileループで書いても良いと思います。