Created
April 22, 2015 16:43
-
-
Save notcome/66322c99fdc91e5b72a8 to your computer and use it in GitHub Desktop.
陆陆的姓名生成器
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Control.Monad.State | |
import System.Random | |
type Range = (Int, Int) -> Int | |
rangify :: Int -> Range | |
rangify x (lo, hi) = x `mod` (hi - lo + 1) + lo | |
getRandomsR :: RandomGen g => State g [Range] | |
getRandomsR = map rangify . randoms <$> state split | |
dropAt :: Int -> [a] -> ([a], a) | |
dropAt n xs = let (heads, (x:tails)) = splitAt n xs | |
in (heads ++ tails, x) | |
replay :: (a -> b -> (b, c)) -> [a] -> b -> [c] | |
replay f [] _ = [] | |
replay f (a:as) b = let (b', c) = f a b | |
in (:) c $ replay f as b' | |
picks :: [Int] -> [a] -> [a] | |
picks = replay dropAt | |
randomPick :: [a] -> Range -> a | |
randomPick xs range = let | |
len = length xs | |
index = range (0, len - 1) | |
in snd $ dropAt index xs | |
randomPicks :: Int -> [a] -> [Range] -> [a] | |
randomPicks n xs stream = let | |
len = length xs | |
ranges = [(0, len - x) | x <- [1..n]] | |
indexes = zipWith ($) stream ranges | |
in picks indexes xs | |
vowelSet = ["a", "o", "e", "u", "i", "y", "an", "on", "en", "un", "in", "yn"] | |
cnsntSet = ["dtθ", "bpfv", "szcj", "xγkg", "mnrl"] | |
shouldAddPrefix :: Int -> Int -> (Int, Bool) | |
shouldAddPrefix 6 _ = (5, False) | |
shouldAddPrefix x 4 = (x - 1, False) | |
shouldAddPrefix x _ = (x, True) | |
intercalate as bs = tail $ foldr1 (++) $ zipWith (\a b -> [a] ++ b) (' ':bs) as | |
buildName vs cs False = intercalate vs cs | |
buildName vs (p:cs) True = p:(intercalate vs cs) | |
randomName :: RandomGen g => State g String | |
randomName = do | |
numV <- state $ randomR (3, 6) | |
dice <- state $ randomR (1, 4) | |
let (numC, hasPrefix) = shouldAddPrefix numV dice | |
vs <- randomPicks numV vowelSet <$> getRandomsR | |
cs' <- randomPicks numC cnsntSet <$> getRandomsR | |
cs <- zipWith randomPick cs' <$> getRandomsR | |
return $ buildName vs cs hasPrefix | |
randomNames = sequence $ replicate 10 randomName | |
main = do | |
stdGen <- getStdGen | |
print $ evalState randomNames stdGen |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> | |
<title>姓名生成器</title> | |
<script> | |
// generate a random integer in [0, upperBound) | |
function random (upperBound) { | |
var x = Math.floor(Math.random() * upperBound); | |
return x; | |
} | |
// generate a random integer in [lowerBound, upperBound) | |
function randomInRange (lowerBound, upperBound) { | |
var seed = random(upperBound - lowerBound); | |
return seed + lowerBound | |
} | |
// identity function | |
function id (x) { return x; } | |
// pick up N elements from an array of elements | |
function pickUpFrom (num, set) { | |
var copy = set.map(id); | |
function work (len, num, array) { | |
if (num == 0) | |
return array.slice(len); | |
var index = random(len); | |
var tmp = array[len - 1]; | |
array[len - 1] = array[index]; | |
array[index] = tmp; | |
return work(len - 1, num - 1, array) | |
} | |
return work(copy.length, num, copy); | |
} | |
// pick up one element from an array of elements | |
function pickOne (set) { | |
var singleton = pickUpFrom(1, set); | |
return singleton[0]; | |
} | |
var vowelSet = ['a', 'o', 'e', 'u', 'i', 'y', 'an', 'on', 'en', 'un', 'in', 'yn'] | |
var consonantSet = [ | |
['d', 't', 'θ'], | |
['b', 'p', 'f', 'v'], | |
['s', 'z', 'c', 'j'], | |
['x', 'γ', 'k', 'g'], | |
['m', 'n', 'r', 'l']]; | |
function randomName () { | |
var numV = randomInRange(3, 7) | |
var dice = random(4) | |
if (numV == 6) | |
{ var numC = 5, hasPrefix = false; } | |
else if (dice == 3) | |
{ var numC = numV - 1, hasPrefix = false; } | |
else { var numC = numV, hasPrefix = true; } | |
var vowels = pickUpFrom(numV, vowelSet); | |
var cnsnts = pickUpFrom(numC, consonantSet).map(pickOne); | |
var result = ''; | |
for (var i = 0; i < numV - 1; i ++) | |
result += vowels[i] + cnsnts[i]; | |
result += vowels[numV - 1]; | |
if (hasPrefix) | |
result = cnsnts[numC - 1] + result; | |
return result; | |
} | |
</script> | |
</head> | |
<body> | |
<button onclick="init()">点击刷新名字列表</button> | |
<ul id="container"> | |
</ul> | |
<script> | |
function init () { | |
var ul = document.getElementById('container'); | |
var html = ''; | |
for (var i = 0; i < 10; i ++) { | |
var item = '<li>' + randomName() + '</li>'; | |
html += item; | |
} | |
ul.innerHTML = html; | |
} | |
init(); | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// generate a random integer in [0, upperBound) | |
function random (upperBound) { | |
var x = Math.floor(Math.random() * upperBound); | |
return x; | |
} | |
// generate a random integer in [lowerBound, upperBound) | |
function randomInRange (lowerBound, upperBound) { | |
var seed = random(upperBound - lowerBound); | |
return seed + lowerBound | |
} | |
// identity function | |
function id (x) { return x; } | |
// pick up N elements from an array of elements | |
function pickUpFrom (num, set) { | |
var copy = set.map(id); | |
function work (len, num, array) { | |
if (num == 0) | |
return array.slice(len); | |
var index = random(len); | |
var tmp = array[len - 1]; | |
array[len - 1] = array[index]; | |
array[index] = tmp; | |
return work(len - 1, num - 1, array) | |
} | |
return work(copy.length, num, copy); | |
} | |
// pick up one element from an array of elements | |
function pickOne (set) { | |
var singleton = pickUpFrom(1, set); | |
return singleton[0]; | |
} | |
var vowelSet = ['a', 'o', 'e', 'u', 'i', 'y', 'an', 'on', 'en', 'un', 'in', 'yn'] | |
var consonantSet = [ | |
['d', 't', 'θ'], | |
['b', 'p', 'f', 'v'], | |
['s', 'z', 'c', 'j'], | |
['x', 'γ', 'k', 'g'], | |
['m', 'n', 'r', 'l']]; | |
function randomName () { | |
var numV = randomInRange(3, 7) | |
var dice = random(4) | |
if (numV == 6) | |
{ var numC = 5, hasPrefix = false; } | |
else if (dice == 3) | |
{ var numC = numV - 1, hasPrefix = false; } | |
else { var numC = numV, hasPrefix = true; } | |
var vowels = pickUpFrom(numV, vowelSet); | |
var cnsnts = pickUpFrom(numC, consonantSet).map(pickOne); | |
var result = ''; | |
for (var i = 0; i < numV - 1; i ++) | |
result += vowels[i] + cnsnts[i]; | |
result += vowels[numV - 1]; | |
if (hasPrefix) | |
result = cnsnts[numC - 1] + result; | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Pattern-match, especially at function decl level, is very convenient. (Hs over Js)
It's essential to have enough utility functions, like those in Prelude and Underscore.js. (Hs over Js)
Carefully controlled side-effects can significantly reduce LoC (Js over Hs), though it is hard to control side-effects.
Functional reactive programming is an interesting concept I should learn.