haskell-jp / beginners #22

@j.nakajima has joined the channel
@naoya has joined the channel
Reminder: beginnersチャンネルは、新しい人がスムーズにHaskellに慣れるための質問を歓迎するチャンネルです。 Haskell-Beginners ML や IRCの#haskell-beginners  や RedditのMonthly Hask Anythingのような位置づけを意図しています。 beginnersチャンネルでの回答側は、以下の左側のような応答を厳禁とする運用です。 • それはくだらない質問だ → くだらない質問など無い • その質問は以前にもあった → 質問者はそんなこと知らない • Google検索せよ → 検索できないから質問している beginnersチャンネルでは、例えば以下のレベルの質問から歓迎します。 • : とは何のことですか。 • タプルとは何ですか。
Haskellでのデバッグ方法がわからず、質問させていただいてもよろしいでしょうか。
やりたいことは、JavaScriptの`console.log`のように、関数のなかの変数を`GHCi`のコンソールに出力したいです。
具体的には、以下の関数で、`repeatedL1` の部分がどんな値になっているかを見たいです。
cartCombine :: (a -> b -> c) -> [a] -> [b] -> [c]
cartCombine func l1 l2 = zipWith func newL1 cycledL2
    where
        nToAdd = length l2
        repeatedL1 = map (take nToAdd . repeat) l1
        newL1 = mconcat repeatedL1
        cycledL2 = cycle l2

ここで、
repeatedL1 = map (take nToAdd . repeat) l1
show repeatedL1
newL1 = mconcat repeatedL1
……

などとすると、エラーになってしまいます。

ご教示いただけますと幸いです。
よろしくお願いいたします。
... Replies ...
Practical Haskell という本を読んでいます。分からない点があるので質問させてください。

module Main (main) where

import GHC.IO.IOMode (IOMode(ReadMode))
import GHC.IO.Handle (hGetContents, hClose)
import  (openFile)

main :: IO ()
main = do
    h <- openFile "./some.txt" ReadMode
    s <- hGetContents h
    hClose h
    print s

これを実行するとエラーになります。`./some.txt: hGetContents: illegal operation (delayed read on closed handle)`

エラーになる理屈は理解していて、`hClose h`と`print s`を入れ替えれば動作します。
他の解決策として seq または deepseq を使っても解決できると書いてあるのですが、具体的に使い方は書いてありませんでした。

hClose h する前に文字列全体を読み込めばいいので、`let !size = length s` を追加して、文字列全体を読み込むように処理を強制しました。これは動作しました。
{-# LANGUAGE BangPatterns #-}
module Main (main) where

import GHC.IO.IOMode (IOMode(ReadMode))
import GHC.IO.Handle (hGetContents, hClose)
import  (openFile)

main :: IO ()
main = do
    h <- openFile "./some.txt" ReadMode
    s <- hGetContents h
    let !size = length s
    hClose h
    print s

let !size = length s を追加したのと同じ理屈で let ds = s deepseq` s` を追加したのですが、これだとエラーになります。

{-# LANGUAGE BangPatterns #-}
module Main (main) where

import GHC.IO.IOMode (IOMode(ReadMode))
import GHC.IO.Handle (hGetContents, hClose)
import  (openFile)
import Control.DeepSeq

main :: IO ()
main = do
    h <- openFile "./some.txt" ReadMode
    s <- hGetContents h
    let ds =  s `deepseq` s
    hClose h
    print ds

let ds = s deepseq` s` ではエラーになる理由をご教示いただけないでしょうか。よろしくお願い致します。
... Replies ...
遅延評価についてよく分からなくなってきました。
module Main (main) where

import qualified  as SIO

main :: IO ()
main = do
    h <- SIO.openFile "./input.txt" SIO.ReadMode
    content <- SIO.hGetContents h
    SIO.hClose h
    print content

これは実行するとエラーになる理由はわかります。`content` を評価する時には既にファイルがクローズされているから。

module Main (main) where

main :: IO ()
main = do
    putStrLn "please input1 "
    input <- getLine
    putStrLn "please input2 "
    putStrLn $ "your input is " ++ input

同様に考えて、 inputを評価する時に標準入力を受け付けることになり、下のような出力順になるのでは?と考えたのですが、
そうはならず。コードに書いてある順序通りの出力になりました。

please input1 
please input2 
your input is aaa

これまでちゃんと理解せずにいたのですが、混乱しています。

getLineがlazyではないから評価された時点で入力待ち状態になる、と考えると納得できそうですが、
そもそも getLine が評価されるのは「please input2」 を出力した後なのでは?
たぶん「遅延評価」「式を評価する」ということの意味を正確に理解できていないと思うのですが、どなたかご教示いただけないでしょうか。
... Replies ...
@mochizuki has joined the channel
Yoshikuni Kato
\
@gnkm has joined the channel
@Jake Lengyel has joined the channel
こんばんは。 Write Yourself a Scheme in 48 hours をやっています。記事中では String が使用されていますが、代わりに Text (データ型) を使ってみたいと思います。
ただ実際使おうにも、 1 文字を表すのに Char を使うべきか Text.singleton かなど迷う点が多くありそうです。
... Replies ...
(そのためインプットが欲しいと思います)。 TextParsec を使ったおすすめのリポジトリなどあれば、お聞かせ願えますでしょうか :eyes:
@ has joined the channel
意外とリポジトリが見つかりました (, lox) 。 String をパースして Text で保存するみたいなものが多い気がします。 Parsec で String ではなく Text を受け取ることは珍しいのでしょうか……? よくあることなら探してみたいと思います :pray:
えっと、ご所望のparsecを使ったものではないですが、パーサーコンビネーターの初歩的な概念を学ぶために、 https://www.lambdanote.com/products/haskell の第13章などの本を読むのがおすすめです。Haskellの世界にはparsec以外にも、もっと新しいmegaparsecなどいろいろなパーサーコンビネーターがありますが、基本的な使い方や考え方は全く変わらないので、サンプルとしては十分だと思います。 Text でやろうと String でやろうとも基本は変わりませんし。
そうですね、そちらの本も持っているのでじっくり読んでみます。ありがとうございます。
と思いきや、今コンパイルが通りました。 Text.ParseCombinators.Parsec の代わりに Text.ParsecText.Parsec.Text を import したら良かったみたいです……?
大分怪しいですが進んでみます……! ()
... Replies ...
パラメータ多相とアドホック多相の違いについて質問させてください。
自分の理解では、パラメータ多相は「いろんな型から利用でき、全く同じ動きをする多相性」で、アドホック多相は「いろんな型から利用でき、それぞれで動きが異なる多相性」のことだと思っています。
この認識はあっていますでしょうか?

また、上記の認識と今まで見てきた情報を総括して個人的なイメージとして「Haskellはパラメータ多相、JavaとかC++などのクラスベースオブジェクト指向はアドホック多相」という風に思っていました。(こういう紹介をしていた情報源もどこかで見たことがあった気がしています。)
ですが、例えばジェネリクスを使って型Aの変数をそのまま返す関数を作れば、これはパラメータ多相っぽいのでは?と思いました。
また、`fmap`はそれを実装したい型ごとに instance 構文でそれぞれの型用の動きを記述するため、`fmap`はアドホック多相っぽいような気がしています。
そうなりますとパラメータ多相やアドホック多相は関数型やオブジェクト指向などの考え方とは独立したものになる感じでしょうか?
... Replies ...
すみだわら
@すみだわら has joined the channel
@Sasaki has joined the channel
Nobuyuki Horiuchi
@Nobuyuki Horiuchi has joined the channel
@Ichiro Hasuo has joined the channel
こんにちは。
VSCodeでのstackのエラーが出て、解消できず困っております。
何かご教示いただけますと幸いです。
Haskell自体の環境設定は、GHCupを使っています。

環境
Windows 11 WSL2 上の Ubuntu 20.04

バージョン
stack 2.9.1
ghcup 0.1.18.0

再現方法

stack new palindrome-checker

で新規プロジェクト作成

app/Main.hs

で以下のようなエラーがでます。
キャプチャ

ghcide compiled by GHC 9.0 failed to load packages: <command line>: cannot satisfy -package palindrome-checker-0.1.0.0
    (use -v for more information). 
Please ensure that ghcide is compiled with the same GHC installation as the project.cradle

バージョンの不整合が起こっているようでいろいろ調べたのですが、
ghcide がアーカイブになっていたりよくわかりません。

https://github.com/haskell/ghcide

ghcのバージョンについても調べました。
以下の二つのコマンドでGHCのバージョンが異なるようでこれも謎でした。

> ghc -v
Glasgow Haskell Compiler, Version 9.4.3, stage 2 booted by GHC version 9.2.2

> stack ghc -- --version
The Glorious Glasgow Haskell Compilation System, version 9.0.2
... Replies ...
@S.K. has joined the channel
@ya-poo has joined the channel
@yskoht has joined the channel
@kino has joined the channel
こんばんは。 State モナドの質問です。 mapAccumLmapMState モナドで作り直してみました。
このとき mapM使用した無名関数 が長くて気になりました。もしも`\acc x -> .. (acc', x')` のような純粋な関数を State モナドに?変換できたら、 mapM (変換 $ \acc x -> .. (acc', x')) .. のように書けて便利だと思います。この 変換 のような関数はありますか? よろしくお願いします。
... Replies ...
最終的には `Vector` に対する `mapAccumL` が欲しくて、それが `mapM` と高階関数で in-place に書けるとさらに嬉しいです _(._.)_
@佐々木哲 has joined the channel
@荒井柚月 has joined the channel
@ひらつか has joined the channel
はじめまして。プログラミングHaskell第2版を読み始めました。1章のqsortについて早速質問させてください。
qsort[]=[]
qsort(x;xs)=qsort smaller ++[x]++qsort larger
 where
  smaller = [a | a<- xs,a<=x]
  larger  = [b | b<- xs,b>x]

でqsortを定義していますが、この定義はGHCiに直接書き込む物ですか?
... Replies ...
double x = x + x
listdouble (x:xs)=[double x] ++ listdouble xs 

によってリストの各要素を二倍にする関数を定義しようとしてみたのですが、エラーが生じてしまいました。具体的には
listdouble [1,2,3,4]

をGHCiでコンパイルすると
[2,4,6,8*** Exception: <interactive>:41:1-43: Non-exhaustive patterns in function listdouble

というエラーが生じます。定義が間違っていると思うのですが、何が間違っているのか理解できずにいます。
... Replies ...
@N gest has joined the channel
アカウントを変えました。プログラミングHaskell第二版を読み終えた後、いろいろ演習問題を解きたいと思っているのですが、何かいい教材やサイトはありますか?
... Replies ...
@ has joined the channel
do構文の外側で定義した純粋関数にIO a 型の引数を渡す方法について知りたいです。paizaの問題 を解いていて、解答として
f :: Int -> Int -> String
f distance stride_length = if distance * 100000 `div` stride_length >= 10000 then "yes" 
                            else "no"
main = do 
       putStrLn "歩いた距離(km)を入力"
       distance <- readLn :: IO Int
       putStrLn "歩幅(cm)を入力"
       stride_length <- readLn :: IO Int
       return (f distance stride_length)

を提出しました。GHCiにベタ貼りすると、一応このコードでも動きはするけど、解答としては不正解らしいのです。
... Replies ...
@ has joined the channel
@木村奏 has joined the channel
@HIJIRI KAWAI has joined the channel
Reminder: beginnersチャンネルは、新しい人がスムーズにHaskellに慣れるための質問を歓迎するチャンネルです。 Haskell-Beginners ML や IRCの#haskell-beginners  や RedditのMonthly Hask Anythingのような位置づけを意図しています。 beginnersチャンネルでの回答側は、以下の左側のような応答を厳禁とする運用です。 • それはくだらない質問だ → くだらない質問など無い • その質問は以前にもあった → 質問者はそんなこと知らない • Google検索せよ → 検索できないから質問している beginnersチャンネルでは、例えば以下のレベルの質問から歓迎します。 • : とは何のことですか。 • タプルとは何ですか。
@t.yamaguchi has joined the channel
@K.N has joined the channel
@miyamonz has joined the channel
@Yuto YOSHIDA has joined the channel
@ has joined the channel
@kk has joined the channel
@gan20 has joined the channel