関数型プログラミング言語Haskell Part33

■ このスレッドは過去ログ倉庫に格納されています
1デフォルトの名無しさん
垢版 |
2020/02/10(月) 18:17:36.49ID:L6eYQqyh
関数型プログラミング言語 Haskell について語るスレです。

Haskell Language(公式サイト)
https://www.haskell.org/
日本Haskellユーザーグループ - Haskell-jp
https://haskell.jp/

前スレ
関数型プログラミング言語Haskell Part32
https://mevius.5ch.net/test/read.cgi/tech/1548720347/
669デフォルトの名無しさん
垢版 |
2021/01/21(木) 06:30:57.22ID:mwzMDOkA
https://stackoverflow.com/questions/35027952/why-is-haskell-ghc-so-darn-fast
この辺
> thanks for the link.
80 lines is what I called "low-level style of programming not much different than
programming in C itself." . "the higher level code",
that would be the "stupid" fmap (length &&& length .
words &&& length . lines) readFile.
If that was faster than (or even comparable to) C,
the hype here would be totally justified then.
We still need to work hard for speed in Haskell as in C, is the point.

>>605もそんなことをかいてる
670デフォルトの名無しさん
垢版 |
2021/01/21(木) 06:38:11.58ID:mwzMDOkA
以下の厳密というのは遅延評価じゃなくするという事だろう?
しかも「プロファイルを作成して改善」は一度アプリを書いてから実行の様子を観察して最適化していくという事だろう。
抽象的にHaskellらしく書いていきなり速いというわけではないという事だ。
プロファイラーでボトルネックを特定して特殊なコードに変えていけば速くなる、と。

>はい、怠惰はおそらくナイーブなHaskellが遅い最大の理由であり、
最適化されたHaskellでさえ速度の点で信頼できない可能性があります。
そのため、パフォーマンスが重要なアプリケーションにはお勧めしません。
OCamlの方が適しています。繰り返しになりますが、
HaskellをBangPatternsなどで厳密にすることはそれほど難しくありません。
また、コードの読み取りや保守が難しくなることもありません。
したがって、パフォーマンスが望ましいが、遅いプロトタイプでも問題がない場合は、
Haskellが非常に良い選択です。うまく機能するものを一緒にハックしてから、
プロファイルを作成して改善します。
671デフォルトの名無しさん
垢版 |
2021/01/21(木) 08:18:51.22ID:mwzMDOkA
こういう認識
・Haskellはコードだけでは最適化ポイントを見つけれない
・最適化したら変なコードになる
・普通のHaskellコードはベンチで他言語に惨敗する
672デフォルトの名無しさん
垢版 |
2021/01/21(木) 09:21:08.07ID:mwzMDOkA
これも
・最適化の方法が処理系(GHC)次第で決まり、プログラマーの認識内に無い。
GHCに対してひたすらトライアンドエラー
2021/01/21(木) 21:44:08.46ID:AWFMWVQb
・Haskellが欲しかったポジションはなんかPythonにとられてしまった
2021/01/22(金) 00:20:12.86ID:IysdrbOG
HaskellとPythonは似ていないから両方使ってもDRYに違反しない

似たもの同士で馴れ合い、異質なもの同士を分断するやつは信用できないが
Pythonは似たもの同士でしっかり競争して生き残ったやつだから信用できる
2021/01/22(金) 01:34:45.31ID:Zh6FWeVu
pythonがなかったとしてもhaskellがそのポジションになることはなかっただろう
2021/01/22(金) 02:27:11.57ID:XLcorGPG
欲しかったHaskell
・型を最大限に活用、バグが無いことを保証しつつ自然にC言語並みの性能も出る
2021/01/22(金) 08:04:15.32ID:RWrydEj5
Haskellerのキモオタ「シグネチャァ」
2021/01/22(金) 12:35:37.28ID:Erx3tlcS
醜悪な表現が得意な奴って、綺麗な表現だとポエムとか言われる恐怖を煽られた結果なのかなと
ふと思った
2021/01/23(土) 13:17:02.46ID:u7XOzuV6
>>665
ListT を使えばと思ったけどだめだった。
・参考
https://blog.mudatobunka.org/entry/2018/01/03/233314
・残骸
module Rand2 where

-- stack install list-t
-- stack exec ghci

import Control.Monad.IO.Class ( liftIO )
import ListT ( ListT, toList )
import System.Random ( Random(randomIO, randomRIO) )

t1 :: ListT IO Int
t1 = return 3

t2 :: ListT IO Int
t2 = liftIO (randomIO :: IO Int)

t3 :: ListT IO [Int]
t3 = repeat <$> t2

output :: ListT IO [Int] -> IO ()
output t3 = do
li0 <- toList t3
print $ take 10 $ head li0
2021/01/23(土) 22:12:27.68ID:u7XOzuV6
>>679
できたー!
module Rand2 where

-- stack install list-t
-- stack exec ghci

import Control.Monad.IO.Class ( liftIO )
import ListT ( ListT, toList, cons, take )
import System.Random ( Random(randomIO) )

t2 :: ListT IO Int
t2 = liftIO (randomIO :: IO Int)

t3 :: ListT IO Int
t3 = do
x <- t2
cons x t3

output :: IO ()
output = do
li <- toList $ ListT.take 10 t3
print li

{-
*Rand2> output
[7616927328998369033,6970782903781268443,-1509938769401207081,-2789264750098693865,-6524417077297424569,8403979199680420436,-3097298192134792937,-2736699795503652525,-4754186463647322678,5658901448509988002]
-}
681デフォルトの名無しさん
垢版 |
2021/01/24(日) 10:57:12.77ID:EEhZoft7
自分の理解が根本的に間違ってるかもしれんけど
haskellは宣言型で実効順序が定まっていないみたいな話を聞いたんだけど
do記法は普通に上から下に実行されるというイメージになるの?

main = do
x <- readLn
x2 <- readLn

こういう風に書いた場合、最初に入力したものがxに入り、その順番は入れ替えれないはず
do記法はほとんど命令型じゃないの?

IOモナドとかに入力されていくアクション列はその順番を入れ替えれないよね?
どんな感じでコーディングされてるか知らないけど
副作用があるところでは順番を入れ替えれないはず、即ち命令型と大差ないはず
2021/01/24(日) 12:14:30.84ID:3w4a632B
>>680
おお、できるんですか!?
すげー
残念ながらいまListT使えないので環境整理してやってみます
2021/01/24(日) 13:21:27.07ID:vsDmG4Mq
>>681
do記法という言語機能は、上から下への命令の実行を記述するものではない
モナドの組み合わせ方を宣言しているだけ
IOのようなモナドの定義に対してはたまたま命令型言語のようになるだけ
言語レベルで命令を上から下へ実行しているわけではない
684デフォルトの名無しさん
垢版 |
2021/01/24(日) 15:49:32.04ID:EEhZoft7
じゃあ標準入力から来た文字列の1行目と2行目を分けて扱うにはどう書くの?
2021/01/24(日) 16:19:42.60ID:QSDOehpN
ListT.toListの引数には有限のリストしか渡せないんだろう多分
現に
li <- toList t3
print (take 10 li)
ではなく
li <- toList $ ListT.take 10 t3
print li
と書いてある
2021/01/24(日) 16:51:40.79ID:o8L11MsB
>>685
> ListT.toListの引数には有限のリストしか渡せないんだろう多分
> 現に
> li <- toList t3
> print (take 10 li)
> ではなく
> li <- toList $ ListT.take 10 t3
> print li
> と書いてある

確認したところ、おっしゃる通り、
前者では応答が返ってきませんでした。
(ListT.repeat でも同じ結果だったので、t3 が悪いのではないです)

> ListT.toListの引数には有限のリストしか渡せないんだろう多分
これで合っていると思います。
2021/01/24(日) 23:50:31.64ID:3w4a632B
やっぱり無理なんですかねぇ?
例えば以下は通るので ”IO 無限リスト” が原理的に無理なわけではないとは思うんですけど

list = return $ repeat '3'

main = do
x <- list
print $ take 10 x

何がどう違うもんなんでしょう?
2021/01/25(月) 09:17:23.58ID:xOoQiCMv
すいません
無限ランダム整数列の件ですが方法がありました
というかSystem.Randomの中に最初から用意されてました
自作でランダム有限列作っておられた方のブログ見つけたので無限列なんて用意されてないとすっかり思い込んでました
以下の方法で1〜10の長さ100の乱数列が簡単に作れるようです
第一引数に値の範囲、第二引数に乱数の種を仕込みます
乱数の種は
mkStdGen :: Int -> StdGen

getStdGen :: IO StdGen
newStdGen :: IO StdGenSource
で作成すれば良いようです
乱数の型はIntだけでなくDoubleなどでも作れるようです

----
import System.Random

randomInts :: StdGen -> [ Int ]
randomInts = randomRs (1,10)

main = do
ris <- ( return . randomInts ) =<< getStdGen
print $ take 100 ris
2021/01/25(月) 09:36:17.94ID:lGPRZ7j1
種が IO だから、
randomRs の戻りは [a] なんだね
2021/01/25(月) 11:51:44.88ID:crCxtFmd
ライブラリは暗記ですが、数学は暗記ですか?っていう定番のあれだな
2021/01/25(月) 13:32:32.62ID:/TZZteD8
>>684
newStdGen :: IO StdGenSource
↑ワロタw
コピペするとよくあるわw
2021/01/25(月) 13:33:07.46ID:/TZZteD8
安価ミス>>688
2021/01/27(水) 00:16:50.20ID:UiZI3fhW
dp の質問です
haskell でdynamic programing する方法の例でFibonacci数列の計算を

fib = 0:1:( zipWith ( + ) ( drop 0 fib ) ( drop 1 fib ) )

で計算させるというテクニックを紹介しているページがあってなるほどなぁと感心しました
で同じテクニック使ってcomb6 !!i !! jが二項係数C[i, j]になる配列

comb6 = ( ( 1 : ( repeat 0 ) ) : )
$ zipWith ( zipWith ( + ) ) comb6 ( map ( 0 : ) comb6 )

を作ってみました
コレはうまくいきます
comb6 !! 2000 !! 1000
とかも一瞬で計算してくれます
でcomb7 !! i !! j が二項係数C[ i+ j, i ]となる配列comb7を

comb7 = ( ( repeat 1 ) : )
$ zipWith ( zipWith ( + ) )
( comb7 )
( tail $ map ( 1 : ) $ comb7 )

と定義してやってみると、compileまでは通るのですが実行comb!!1!!0すると<<loop>>と言われて止まってしまいます
しかし手計算で展開してみてもloopしてないと思うんですけどどこがおかしいのかわかりません
どなたかわかりませんでしょうか?
2021/01/27(水) 11:32:01.04ID:fGEABlaN
comb7 = x : xs
xs = zipWith f comb7 ys
ys = tail zs
zs = map g comb7
zs = map g (x : xs)
= g x : map g xs
ys = tail (g x : map g xs)
= map g xs
xs = zipWith f comb7 (map g xs) -- ここで(map g xs)のパターンマッチができない
2021/01/27(水) 12:36:29.90ID:UiZI3fhW
>>694
ありがとうございます
しかしどうもパターンマッチに失敗してるようではないようです
実際コンパイラは型推論に成功してるように見えますし、明示的に
comb7 :: [[ Int ]]
を入れてもダメです
実行時のエラーメッセージも
Non-exhaustive patterns
ではなく
prog : << loop >>
が表示されています
2021/01/27(水) 13:52:31.92ID:fGEABlaN
こういう時は自分の考えに自信を持つことも必要
誰かがエラーメッセージを見ている(または見ていない)のを見たからといって簡単に考えを変えない方がいい
2021/02/02(火) 01:48:19.32ID:yyMOWUoH
fixの定義は fix f = let x = f x in x となっていますが、
この x 自体は再帰的に定義されていると言えますか?
2021/02/02(火) 16:19:31.38ID:ErrealWs
>>693
xs0 = repeat 1
xs1 = zipWith (+) xs0 (0:xs1)
xs2 = zipWith (+) xs1 (0:xs2)
xs3 = zipWith (+) xs2 (0:xs3)

こんな感じに個別に定義すれば確かに計算できるので、
comb7 !! 1 を計算するのにcomb7 !! 1 が必要だぞという点を
怒っているような気がするのだが確かなことは言えない、すまぬ

comb6 !! n は計算するのに comb !! (n-1) の情報だけで十分なところが違うので
2021/02/02(火) 17:58:42.89ID:AZLuBdJH
>>697
再帰的と言うのは木構造を想定している気がする
そのコードはグラフ簡約のためにそうなったので木構造でも再帰的でもないと思う
2021/02/02(火) 22:40:39.64ID:LQ6cge6d
>>698
ありがとうございます
私も多分それが原因かなと思い始めてます
一回目のcomb7 !! 1 と二回目では続く添字が! !!2 から !!1 に減ってるのですがHaskellはそんな事は勘案せずに「comb7 !! 1の展開の中にcomb7 !! 1が出てきたからアウト」と言ってるのかなと
つまりはこの手の二重漸化式はHaskellはそのままズバリでは読んでくれないんでしょうね
2021/02/03(水) 00:23:45.54ID:QKvl77B6
comb7 !! 1 を計算するには length comb7 >= 2 のようなものが必要だぞ
でも長さは1かもしれないからアウトという判断は正しい
オーバーランするよりよっぽどいい
2021/02/03(水) 14:08:13.61ID:mxabq2OH
求めてないかもですがこんなふうならかけますね。
module Main where
import qualified Data.Array.Unboxed as AU
main = do
print $ comb6 !! 2000 !! 1000
print $ comb7_1 !! 1000 !! 1000
print $ comb7_2 1000 1000 AU.! ( 1000, 1000 )
comb6 = ((1 : (repeat 0)) :) $ zipWith (zipWith (+)) comb6 (map (0 :) comb6)
comb7_1 = (repeat 1 :) $ ([ 1 .. ] :)
$ (map (\x -> scanl (+) 1 $ tail x) $ tail comb7_1)
comb7_2 :: Int -> Int -> AU.Array ( Int, Int ) Integer
comb7_2 ly lx = comb7_2_table
where
comb7_2_table = AU.array ( ( 0, 0 ), ( ly, lx ) ) $ concatMap(\i -> map (f i) [ 0 .. lx ]) [ 0 .. ly ]
f 0 x = ( ( 0, x ), 1 )
f y 0 = ( ( y, 0 ), 1 )
f y x = ( ( y, x ) , comb7_2_table AU.! ( (y - 1), x ) + comb7_2_table AU.! ( y, (x - 1) ))
2021/02/04(木) 22:24:53.84ID:w5MK0dgi
>>702
ありがとうございます
参考にさせていただきます
そうですね
もう一つ可読性が欲しい感じがします
元々の問題意識としては私は可読性の高いコードが要求されることが多いのです
例えばFibonacci数列であれば

f n = ( f $ n -1 ) + ( f $ n - 2 )

に可読性においてまさるものはないのですが、もちろんこれでは遅くて使い物になりません
なので実用性も多少はなりとも求めるならある程度は可読性を犠牲にせざるを得ないのですが、どういう方法がいいのだろうというのがテーマなのです
でたまたまFibonacciの場合に
f = 0 : 1 : ( zipWith ( + ) f $ tail f )
というのを見つけてコレ中々いいなと、dpで計算してるのに“メモ”をするための不要な手続きを書く必要がなく、Haskellの“call by need”の機能をうまく利用してdp計算させてるところにちょっと唸ったもので
でどれくらいコレでいけるのかなと二重数列をやってみたらうまくいかなくて、どうしたもんかなと
まぁコレはしょうがないのかもしれませんけど
2021/02/05(金) 00:47:44.85ID:hZ1aOePg
>>703
方向性違うかなと思いつつ書いたんですがやっぱり違いましたね。失礼しました。
今更どうでもいいですがちょっと間違えたので訂正だけさせてください。
comb7_1 = (repeat 1 :) $ (map (scanl (+) 1 . tail) $ comb7_1)
2021/02/05(金) 01:12:53.20ID:gzN36RyX
読むという目的
可読性の低いコードを、読むことなく却下するという手段

この目的と手段がすぐ入れかわってしまう現象もまた深刻な問題だ
2021/02/05(金) 06:11:52.56ID:5jF91Ui3
速さを求めてnconcみたいなもんだな
2021/02/05(金) 19:44:21.42ID:DBOaHn9B
>>703
その遅くて使い物にならない計算を、
可読性をあまり犠牲にしないで爆速にする方法に、
メモ化(memoization)というテクニックがあります。
(その代わり、当然メモリを使います)

メモ化関数 memoize が用意されていれば、
n 番目のフィボナッチ数を求める関数 fib は
次のように書けます。

-- メモ化
fib :: Int -> Integer
fib = fix (memoize . fib')

-- フィボナッチ計算の本体
fib' :: (Int -> Integer) -> Int -> Integer
fib' f 0 = 0
fib' f 1 = 1
fib' f n = f (n-1) + f (n-2)

メモ化関数を提供するパッケージは色々あります。
また、メモ化の仕組みの基礎や本質を学びたいのなら、
次のごく短いブログ記事がおすすめです。
https://kseo.github.io/posts/2017-01-14-memoization-in-hasekll.html
この記事の最後の fibMemo 関数について、
適当な小さな値に適用させたものを
自分でノートに展開してみるといいです。
2021/02/05(金) 20:00:27.08ID:DBOaHn9B
>>707
すいません。
肝腎の memoize 関数の定義を書き忘れました。

memoize :: (Int -> a) -> (Int -> a)
memoize f = (map f [0 ..] !!)

先に紹介した記事にこれを導く過程や、
より速くより一般化する方法を学びたい人へ向けた
URL紹介が載っています。
2021/02/06(土) 09:10:00.64ID:8eeMDweD
>>707
解説ありがとうございます
やはりメモ化するしかないんだと思います
問題はそれがプログラマが明示的に自分でやらないといけないのか、コンパイラが自分でやってくれるのかの差なんだと思います
Haskellは純粋なcall by nameではなく、call by needのシステムの中にメモ化を備えていてプログラマがメモ化するように書いてなくても勝手にメモ化できるものをメモ化してくれるのがすごいとこだと思うんですけど、例えば>>703の2番目の例で最初見た時「なんでこの定義式でメモ化が効くんだ?」とさっぱりわからなかったのが、実はHaskellのcall by needのシステムをうまく利用してるらしいとわかったのが最初なんです
で二重の漸化式だとうまくいかないなと
もちろん二重の全炊きでも上手くsuffixの取り方を変えたりすると同様の方法でメモ化できるんですけど、それでは結局「Haskellの機能を利用して明示的にメモ化を指定することなく高速化した」事にはなりません
まぁコレはしょうがないんでしょうね
どんな計算も常にメモ化して常に同じ評価式を2度扱う事を防いでたらそんなの逆に使い物になりませんからね
2021/02/06(土) 20:56:07.58ID:tGZHMqQF
Haskellが「ヤバそう」って偏見だけで敬遠されてるのかなしい…
同級生にも布教したい
2021/02/06(土) 21:00:00.51ID:xuEfQm7n
>>710
布教という言葉自体、独善的で押し付けがましく感じられる原因になってると思うよ。
相手がいやがらない程度にhaskellの良さや面白さを伝えてそれでも相手が興味をひかれないなら、それ以上はやめときな。
2021/02/06(土) 21:12:54.72ID:HlAr7yEc
>>709
今回の話の本質ではないので、へーそうなんだ、
程度に聞いてくれればいいのですが、

>>703 の2番目の例とは、

f = 0 : 1 : zipWith (+) f (tail f)

のことでしょうか。
もしそうなら、これはメモ化ではないですよ。
(このテクニックをなんと呼ぶのかは知りませんが)

メモ化というのは簡単にいえば、
関数の同じ引数に対する2度目(以降)の適用に備えて、
その引数に対する1度目の関数の値をその引数とペアにして
どこかにメモしておくことです。

ポイントは、2度目以降に備えることではなく、
引数と関数値のペアをメモしておくことです。

それを踏まえて、>>703 の2番目の例において、
では何が関数で、引数と関数値のペアはどこにメモされているか、
考えてみてください。


ただ、言葉の意味は時代と共に変化していくものなので、
今はこれも広義にメモ化と言うことになっているのでしたら、すいません。
私の方が勉強不足です。
2021/02/07(日) 08:28:27.99ID:kgbg5mk/
>>707の方がzipwith使ったものより読みやすくて遥かにいいな
こっちの書き方の方がもてはやされてほしいわ
2021/02/07(日) 10:58:25.84ID:nblMEePQ
久しぶりにHaskell(Servant)触ってみたけど
相変わらず呪文のようなテンプレートマクロとかコンパイル通すためだけの幽霊型とか表に出てきているのね
こういうの後ろに隠した実装がほちい(・ัω・ั)
2021/02/07(日) 19:10:10.31ID:Ae+USThM
>>714
試しに作ってみればいいのでは?

そういう気に入らない幽霊型を
とりあえず1つだけ後ろに隠してみて、
使いやすいか試してみればいいと思う。

良さそうなら、ここや GitHub で提案するとか。
2021/02/07(日) 21:05:48.19ID:kgbg5mk/
Servant辛いから是非お願いしたい
2021/02/08(月) 03:22:56.40ID:lr3qr0Kv
>>699
レスが遅くなりましてすいません。
xの定義にx自身を参照していますが、それだけでは
再帰的に定義されているとは言えないということですか。

例えば次の関数 f は再帰的に定義していると皆が言います。
f n = if n == 0 then 1 else n * f (n-1)

これと >>697 の x とは何が違うのでしょうか。
2021/02/08(月) 07:06:31.27ID:aZaTrcsy
>>717
fix x はxの定義じゃなくてfixの定義では
2021/02/08(月) 09:04:48.35ID:THE6D9/g
>>718
fix定義の中でlet節を使って定義されているxの話です。
2021/02/08(月) 12:31:08.86ID:hFpKnaPX
>>707
リスト使ったメモ化の理解にはいいんですけど、その例も実は遅いんですよね。!!がO(n)なので。
module Main where
import Data.Function
import qualified Data.Vector as V
main = do
let memo = fibMyMemo 50000
print $memo 50000
print $fibMemo 50000
fibMyMemo l = fib
where
fib = ((V.map f $ V.enumFromN 0 (l + 1)) V.!)
f 0 = 0 :: Integer
f 1 = 1
f n = fib (n -1) + fib (n -2)
memoize f = (map f [0 ..] !!)
fib f 0 = 0
fib f 1 = 1
fib f n = f (n - 1) + f (n - 2)
fibMemo = fix (memoize . fib)
2021/02/08(月) 18:33:31.66ID:USGkiU7i
>>717
マジョリティとマイノリティの違いとか、合法とグレーの違いのようなものだと思えばいいだろ

再帰的な関数と再帰的な型はよく知られている
一方、関数でも型でもないケースは未知のウイルスのようなもので
既存のものと同じだとすぐ決めつけるのは判断が早過ぎる極論
2021/02/08(月) 20:09:46.17ID:xtdfQPSv
>>720
そうですね。

なので、実際は Trie 木でメモする MemoTrie が効率良いと思います。
2021/02/10(水) 06:55:43.73ID:w+SbAYAx
>>721
すいません、結局のところ、どういう事でしょう?
2021/02/10(水) 10:35:38.44ID:tXb64EJq
法律や善悪の判断の正しさを疑うのと同じレベルの懐疑的な思考が
数学やデバッグにも必要ということかな
2021/02/10(水) 11:17:11.88ID:tXb64EJq
静的型は最強とかガベコレは最強とかいう考えが
疑われるようになったのは半分ぐらいHaskellが原因だよね
2021/02/10(水) 13:30:33.82ID:em7GM66H
>>721←こいつまだいたのか
気持ち悪すぎる
2021/02/10(水) 14:18:45.17ID:tXb64EJq
ここは無料だしこんなもんだろ
良いものはみんな課金される
2021/02/11(木) 14:43:11.06ID:/UgD5Hp7
地獄の沙汰も金次第
だが天国への言及はない
2021/02/11(木) 16:56:32.70ID:zBw+qxbZ
ねえ、購入厨
ひょっとしてHaskellは、きみが同じ地獄を繰り返す毎に
強力なフリーソフトになっていったんじゃないのかい
2021/02/13(土) 21:17:16.21ID:kqsb0S1y
悪役キャラには著作権等のコンプライアンスを意識させると邪気が抜けてしまう
豆知識
2021/02/14(日) 18:40:01.75
なぜ Haskell スレはワードサラダ bot に狙われてしまうのか
2021/02/14(日) 20:59:33.34ID:2j5v2BhK
>>731
ネットの差別発言を排除する努力すらやらない人がいるから
ワードサラダとやらを排除する努力なんて誰もやらないのは当たり前だぞ
こんな簡単なことがなぜ理解できないんだ
2021/02/14(日) 21:27:29.30ID:A1oxlP1a
731はワードサラダなレスうぜぇなぁくらいの意味しかなくワードサラダなレスが存在してしまう理由を実際に疑問に思っているわけではないという簡単なことが何故わからないのか
2021/02/14(日) 21:49:22.17ID:2j5v2BhK
731は、うぜぇなぁ以外何も考えてなかったというのか
それは差別意識しかない絶対悪じゃないか
2021/02/15(月) 01:08:13.78ID:Qrz9kKC+
もっと危機感を持ったほうがいいよ
母国語の特徴までネチネチいじられたら外国語はこわくて使えないだろう
英語ができないとプログラミングもできない
2021/02/15(月) 17:23:26.09ID:Mv5LolEs
なんかこのスレ会話が噛み合わないよな
>>732←こいつとか明らかに頭おかしいし
こういう人外化け物がうじゃうじゃいるから「特技はコミュニケーション能力です」みたいなゴミ文系が社会で調子に乗り始めるんだろうな
2021/02/15(月) 18:24:29.13ID:Qrz9kKC+
コミュ力の悪用を止める方法で一番使えそうなのは制限時間を無くすことだ
5秒で答えさせるような問題でも時間のルールを無視してしまえば
そのゴミ文系ってやつの能力を擬似的にコピーできる
2021/02/15(月) 19:02:15.47ID:3zpQr6lX
Haskellの話は?
2021/02/15(月) 20:58:35.44ID:Qrz9kKC+
最小不動点を定義する半順序の定義がない
それと「再帰」の定義がない
2021/02/16(火) 10:45:42.61ID:AZNZAZhP
>>738
こういう話?
ttps://i.imgur.com/oKvfp6x.png
2021/02/16(火) 12:56:19.11ID:VICwQMLs
質問なんですが,
https://levelup.gitconnected.com/functional-dynamic-programming-with-haskell-top-down-and-bottom-up-7ccade222337
の一番上のコード内23-25行目の
iMinusOne <- cdRecursiveTD (i-1) stArr
iMinusTwo <- cdRecursiveTD (i-2) stArr
writeArray stArr i ( (i-1) * ( iMinusOne + iMinusTwo ) )
の部分を添え字使って
for j = 1 to 2
xs !! j <- cdRecursiveTD (i-j) stArr
writeArray stArr i ( (i-1) * ( sum xs ) )
みたいに書く方法ってありませんかね?
2021/02/16(火) 15:13:16.20ID:VICwQMLs
すみません自己解決しました
一応結果貼っておきます
cdRecursiveTD i stArr = do
____v <- readArray stArr i
____when (v == -1) $ do
______xsm <- newSTRef []
______forM_ [1,2] $ \j -> do
________x <- cdRecursiveTD (i-j) stArr
________modifySTRef xsm (x:)
______xs <- readSTRef xsm
______writeArray stArr i ( (i-1) * ( sum xs ) )
____readArray stArr i
2021/02/16(火) 15:27:24.80ID:twhDC3NA
xs <- mapM (\j -> cdRecursiveTD (i - j) stArr) [1 .. 2]
writeArray stArr i ((i - 1) * sum xs)
これでよくないですかー?
2021/02/16(火) 15:32:43.34ID:VICwQMLs
>>743
そっちの方が遥に良いですね…
ありがとうございます
2021/02/17(水) 14:02:08.57ID:YPZ4jTJ4
map f [1,1,1,2]のように重複の多いリストがあったら
fの実装を変える勢力とリストの構造を変える勢力の争いをどうやって解決できるか気になる
2021/02/17(水) 16:20:43.74ID:mAFPwKeZ
一回Set型にしてからListに戻す
2021/02/17(水) 16:22:11.25ID:mAFPwKeZ
もちろんリストの要素の個数減って良い場合の話だけど
2021/02/17(水) 22:40:59.85ID:0SJ3Yct4
>>745
具体的な問題状況(例)が示されなければ、次のような何にでも当てはまる
至極当たり前のつまらない回答しかできないと思うが。

目的、開発リソース(時間や設備、資料、費用など)、
開発者の能力やモチベーション、メンテの容易さなどを、
優先順位を考慮したうえで出来るだけ客観的に評価し決定する。

争うということは、優先順位や評価基準が定まっていないということなので、
まずはそれらを話し合って、あるいは上の立場の者がバシッと決める。
2021/02/18(木) 09:29:03.36ID:8Wc99cSo
なんかしょうもない話なんですけどウチの環境で次が通ります

test x = case x of
_ | odd x -> 1
oyherwise -> 0

main = do
print $ test 123
print $ test 456

なんか笑ってしまいました
2021/02/18(木) 09:31:00.46ID:8Wc99cSo
あ、イヤ違う
勘違いでした
すいません
2021/02/18(木) 10:58:11.75ID:jy6gqPJ4
>>748
客観的な目的というのは難しすぎて誰にも分からない
例えば個人的な借金を減らすことと国の借金を減らすことはどちらが客観的目的か

そうではなく、目的は主観で決めてOKというなら
それは結構面白い答えであって、つまらない答えではない
2021/02/18(木) 11:50:05.23ID:6bd12mxo
>>751
言葉が足りず、誤解させたようで申し訳ない。

客観的に行うのは、目的を定めることではなくて、
今やろうとしている事が定めた目的に合っているのか評価すること。

fの実装を変えることが目的に合っているのか、
それともリスト構造を変える方がより合っているのか。

目的というのは様々あるよね。
見聞きした新しい技術をラフに評価するための
トイプログラムを作ることが目的だったり、
次のリリースでメモリ使用量を10%削減することだったり。

客観的に評価することを意識しないと、気分や雰囲気に流されて、
メモリ使用量を抑える目標が、いつの間にか処理速度向上にすり替わってたりする。

また、目標は評価する一項目にすぎない。
リリース時期を守る方が優先順位が高い状況もある。
だから、もろもろ含めて客観的に評価する。

逆にそうじゃないと、fとリストどちらを変えるのかなんて、決めようがないと思う。
2021/02/18(木) 15:29:22.47ID:jy6gqPJ4
>>752
気分や雰囲気に流されまくるまで想定しておくのが良い作戦だよ
流されないように対策するので想定する必要はないみたいな理屈は危ない
2021/02/25(木) 20:48:36.35ID:zWeVIvWn
ある対象がモノイドかどうかを問う質問です。

2つのリストのうち要素の少ない方のリストをそのまま返す、
同じ要素数ならば左側のリストをそのまま返す関数 f :: [a] -> [a] -> [a] があるとします。
ここで、ある型aのリスト全体の集合[a]と、その上の二項演算fとの組([a], f)はモノイドを成すでしょうか。

私は次のように、これはモノイドではないと考えます。

このモノイド性を考えるとき、その単位元の候補として、
もし集合に無限リストを含めないのならば最大要素数のリストを、
無限リストを含めるのであれば無限リストを取ります。
他に考えようがありません。

しかし、どちらにしても単位元の一意性が証明できません。
xs、ys 共に最大要素数のリスト、あるいは無限リストであり、かつ xs /= ys を満たすものは(型aによっては)いくらでもあります。

よって、([a], f) はモノイドではないと考えますが、これは正しいでしょうか。

モノイドの定義に照らし合わせるのではなく、
モノイドならば証明できるであろう定理が証明できないことに因っているのが、
なんとも気持ち悪いのですが・・・

そもそもモノイド性を問うには ([a], f) の定義が曖昧なのでしょうか。
2021/02/25(木) 21:30:50.20ID:hQOL6Vl7
モノイドではないに一票
2021/02/26(金) 01:35:18.34ID:7R2bTCy0
リストには同じ要素が何個も入ってもいいんだから単位元になり得るのは無限リストだけでしょ
ある無限リストを単位元eとするしかなさそう
ここでもう1つ無限リストaを用意してf a eしたらa返さずに要素の個数比較する時点で⊥になるからモノイドにならないと思う
2021/02/26(金) 02:07:21.86ID:Drny41hT
型は集合ではない
値は元ではない
プログラム上の関数は数学的な意味での関数ではない

Haskellは数学ではない
2021/02/26(金) 10:03:43.32ID:W2dsUZYE
モノイドでも集合論でも、公理が多過ぎて公理が偽になるなら
公理を減らせばいいじゃん
2021/02/26(金) 10:24:37.14ID:nFSf/y++
>>754
まず単位元の定義から、esが[a]の単位元であるなら、任意のxsに対して
f es xs == xs
f xs es == xs
を満たす、というところはいいよね(ゆえにesは、任意のxsより要素数が大きくなければいけない)

このことから直接非存在を言う方がこの場合は明快だと思うけど、
「ある要素が単位元ならばそれが一意である」はすぐに言えるから
背理法により単位元が存在しない、でも正しい論証だと思う

もしこの演算fに対してモノイドを構成するなら、
(>>756とほぼ同じことを言うが) length es == ∞ なる要素を1つ決めて
(全ての有限リスト) ∪ {es}
みたいな集合の上でなら言えそう
ちゃんと見てないけど結合律もそれっぽく振る舞ってそう
2021/02/26(金) 11:29:42.18ID:s/eVhYHX
>>756
>>759
お二方の意見を参考に、もう一度よく考えてみます。
ありがとうございました。
2021/03/18(木) 15:12:33.23ID:4AdjqCpZ
なんか最近プログラミングの情報ネットで漁ってると数学基礎論の記号らしきもの、横棒の上になんか命題らしき文字列が並んでる奴がめちゃめちゃ出てくるんですけど、完全に乗り遅れました
なんかあの記号の意味解説してるいい教科書とかサイトとかありませんか?
2021/03/18(木) 19:10:51.45ID:lKavXNN6
>>761
このような式ですか?

P -> Q P
--------------
Q

これは、横線の上の論理式(この例の場合は2つの論理式)を前提とすると、
いくつかの推論規則を使えば横線の下の論理式が導ける、
という意味です。

論理学の教科書(的な解説サイト)ならレベルの高低に関わらずどれでも載っていますが、
どれでも式自体の意味についてはこの程度の説明しか無いと思いますよ。
例えば
https://abelard.flet.keio.ac.jp/person/takemura/class/2013/3-print-nk.pdf

知りたいことが違っていたらごめんなさい。
2021/03/18(木) 19:28:09.20ID:wWeTTUcP
>>762
ありがとうございます
ギリギリその図形の意味はわかります
問題はそれとプログラミングの理論がどう関わってるかのとこなんです
多分カリーハワード対応というやつだと思うんですが
コレなんか役に立つもんなんですかねぇ?
2021/03/18(木) 20:21:41.37ID:lKavXNN6
>>763
めちゃめちゃ出てくるという事ですので、
そのページのURLをいくつか挙げてくれませんか。

そうすれば、もしかしたら、どう関わっているの把握できて、
説明、あるいは解説ページや書籍の紹介ができるかもしれません。
2021/03/18(木) 20:27:07.75ID:gebFut6o
例えばプログラムをリファクタリングするとき、修正前後での挙動一致を証明できたりするぞ
すごい🤗
(依存型のないHaskellでは出来ないからidrisの例だけど)

https://keens.github.io/blog/2020/12/22/idrisdeizongatawotsukattashoumeinyuumon/

やりたいことが数学/論理学の勉強とかならcoqのほうがよさげ
2021/03/18(木) 23:49:21.36ID:wWeTTUcP
>>764
そうですね
例えばcall by nameとcall by needの違いを調べようと思った時に出てきた

https://reader.elsevier.com/reader/sd/pii/S1571066104000222?token=1C1ACCAE69D33669B7D36179C932FC14DD80723B2FD5B3080E3B1EDED9228FC6A9A6AC347668843625B7154C276B7B4C

なんかバリバリ出てきます
なんのこっちゃと

>>165
coqもよく聞きますよね
なんかおすすめの教科書とかありますか?
2021/03/19(金) 00:48:13.30ID:H+hZ3f68
カリーハワード対応って要は
True => True = True
True => False = False
False => True = True
False => False = True

{単集合->単集合}=単集合 (単集合から単集合への写像は一通りだけ)
{単集合->空集合}=空集合 (単集合から空集合への写像は存在しない)
{空集合->単集合}=単集合 (空集合から任意の集合への写像は一通り(空写像))
{空集合->空集合}=単集合 (上に同じ)
と対応してるって感じと捉えれば良いのかな?
wikipedia読んでもあんまり理解できない
2021/03/19(金) 01:58:47.96ID:MuA020tT
名前呼び出しの意味が分かりません
2021/03/19(金) 02:07:37.96ID:FHn+Zz2I
>>766
結局のところ知りたいことは何ですか?

カリーハワード同型対応とプログラムとの関係性ですか?
それとも、カリーハワード同型対応がプログラムの何に役立つのかですか?
それとも、call by name と call by need との違いですか。
それとも、その論文の内容ですか。
(その場合、PDFの5ページ目まで、つまり横線の式が登場する部分まではちゃんと理解できていると思っていいのですか?)

それとも、全く別のことですか?

とりあえず知りたいことをピンポイントに小さく一つに絞り、
それを具体的に質問していただけると助かります。


ところで、>>768 は元の質問者さんですか?
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況