haskell - 如何在 Haskell 中链接二进制函数?
问题描述
我想使用System.Random.next
函数生成 N 个数字。我实现了一个函数,它接受一个StdGen
和一个数字列表并返回新的生成器和更新的数字列表:
import System.Random
getRandNum :: StdGen -> [Int] -> (StdGen, [Int])
getRandNum gen nums = (newGen, newNums)
where
(randNum, newGen) = next gen
newNums = nums ++ [randNum]
然后我可以通过以下方式使用它:
λ: getRandNum (mkStdGen 1) []
(80028 40692,[39336])
但是我在执行该函数 N 次以获取随机数列表时遇到问题。我怎样才能以正确的方式链接它?
我也尝试了递归方式——它有效,但我确信这个解决方案远非优雅:
randomnumbers_ :: Int -> StdGen -> (StdGen, [Int])
randomnumbers_ 0 gen = (gen, [])
randomnumbers_ 1 gen = (newGen, [randNum])
where
(randNum, newGen) = next gen
randomnumbers_ n gen = (newGen2, nums ++ nums2)
where
(newGen, nums) = randomnumbers_ 1 gen
(newGen2, nums2) = randomnumbers_ (n - 1) newGen
randomnumbers :: Int -> Int -> [Int]
randomnumbers n seed = snd $ randomnumbers_ n generator
where
generator = mkStdGen seed
顺便说一句,是的,我知道它可以使用State
monad 来实现,而且我知道该怎么做。
解决方案
链接它的方法是以您不需要这样做的方式实现它,即它自己进行链接。
无论如何,您的代码中存在固有的矛盾,您称它为getRandNum
单数,它确实只有一个数字,但类型是[Int]
.
因此,我们通过对您的代码进行最少的编辑来解决所有这些问题,如
getRandNums :: StdGen -> [Int]
getRandNums gen = randNum : newNums
where
(randNum, newGen) = next gen
newNums = getRandNums newGen
这种方案是 Haskell 的典型方案,使用所谓的受保护递归以自上而下的方式构建列表,即由惰性数据构造函数(在本例中为:
)保护的递归。像您一样使用重复附加单例构建的列表效率非常低,在访问时具有二次行为。
安全地隐藏在newGen
里面,封装起来,是一个额外的好处。不想暴露,有什么用?无论如何,从中间重新启动随机生成序列只会重新创建相同的数字序列。
当然,您可以根据需要从该列表中删除任意数量的数字,使用take n
.
推荐阅读
- python - ImportError:Python 版本不匹配
- flutter - 单击图标按钮小部件时显示弹出菜单 Flutter
- android - Edittext.gettext 不返回 null
- javascript - How to stop using a plugin in vue?
- javascript - Changing vue component in vendor/ in Laravel Nova
- react-native - RNFetchBlob.fs.mkdir executes successfully but doesn't create directory
- asp.net - Wrong dependency to IIS restart for getting changed data in SQL Server
- bash - 尝试使用 bash 从特定字符串 NumberLong("43494254014573") 中提取数字时出现命令未找到错误
- ios - SwiftUI:如何创建具有相同行数和列数的 LazyGrid?
- flutter - 未定义 Flutter 扩展