如何将 haskell 程序重写为 elixir 程序?我是不是犯了什么错误? [关闭]

问题描述 投票:0回答:0

我在 code-golf 浏览了一个帖子.

我正在尝试在 Elixr 中重写@Christian Sievers 的回答,但是:

我的长生不老药代码

n=1..=5
输出
2,2,1,1,1
,预期
2,2,4,10,28

可以说是一个Elixir语法求助贴。我想我在这里犯了一些错误。

我应该考虑

data Point = P !Int !Int deriving (Eq,Ord)
在 haskell 中,并在 Elixir 中实现它吗?

如何解决?任何帮助将不胜感激。

haskell 代码

{-# LANGUAGE BangPatterns #-}

import Data.List(sort)
import qualified Data.Set as S
import System.Environment(getArgs)

data Point = P !Int !Int deriving (Eq,Ord)

start :: Point
start = P 1 1

redsq :: Point -> Bool
redsq (P x y) = (x+y) `mod` 4 == 2

neighs :: Point -> [Point]
neighs (P x y) =
  case (even x, even y) of
    (False,False) -> [P x (y+1), P (x+1) y, P x (y-1), P (x-1) y]
    (True, False) -> (P x (c y (x+y+1))) : opt [P (x-1) y, P (x+1) y]
    (False,True ) -> (P (c x (x+y-1)) y) : opt [P x (y-1), P x (y+1)]
  where
    opt = filter ok
    ok p = p>start || not (redsq p)
    c z m = if m `mod` 4 == 0 then z+2 else z-2

count :: S.Set Point -> S.Set Point -> [Point] -> Int -> Int -> Int -> Int -> Int
count use _    _            0 c r y =
  if check (S.toAscList use) (y==r)
    then c+1
    else c
count _   _    []           _ c _ _ = c
count use seen (p:possible) n c r y =
  let !c' = count use seen possible n c r y
      new = filter (`S.notMember` seen) $ neighs p
      !r' = if redsq p then r+1 else r
      !y' = if redsq (mirror p) then y+1 else y
      !n' = n-1
  in if r'+n' < y' 
       then c'
       else count (S.insert p use) (foldr S.insert seen new) (new++possible)
                  n' c' r' y'

class Geom g where
  translate :: Int -> Int -> g -> g
  rot :: g -> g
  mirror :: g -> g

instance Geom Point where
  translate dx dy (P x y) = P (dx+x) (dy+y)
  rot (P x y) = P (2-y) x    -- rotate around (1,1)
  mirror (P x y) = P x (-y)

instance (Geom g, Ord g) => Geom [g] where
  translate x y = map $ translate x y
  rot = sort . map rot
  mirror = sort . map mirror

normalize :: [Point] -> [Point]
normalize pol = let (P x y) = head (filter redsq pol)
                in translate (1-x) (1-y) pol

check :: [Point] -> Bool -> Bool
check pol !cm = let rotated = take 4 $ iterate rot pol
                    mirrored = if cm then map mirror rotated else []
                    alts = map normalize (tail rotated ++ mirrored)
                in all (pol<=) alts

f :: Int -> Int
f 0 = 1; f 1 = 2; f 2 = 2
f n = count S.empty S.empty [start] n 0 0 0

output :: Int -> IO ()
output n = putStrLn $ show n ++ ": " ++ show (f n)

main = do args <- getArgs
          case args of
            []  -> mapM_ output [1..]
            [n] -> output (read n)

在线试用!

长生不老药代码

defmodule Point do
  defstruct [:x, :y]

  def new(x, y), do: %Point{x: x, y: y}
end

defmodule Polyominoes do
  alias Point

  def start, do: Point.new(1, 1)

  def redsq(%Point{x: x, y: y}), do: rem(x + y, 4) == 2

  def neighs(%Point{x: x, y: y}) do
    case {rem(x, 2) == 0, rem(y, 2) == 0} do
      {false, false} ->
        [Point.new(x, y + 1), Point.new(x + 1, y), Point.new(x, y - 1), Point.new(x - 1, y)]

      {true, false} ->
        [Point.new(x, c(y, x + y + 1))] ++ opt([Point.new(x - 1, y), Point.new(x + 1, y)])

      {false, true} ->
        [Point.new(c(x, x + y - 1), y)] ++ opt([Point.new(x, y - 1), Point.new(x, y + 1)])
    end
  end

  defp opt(list), do: Enum.filter(list, &ok?/1)
  defp ok?(point), do: point > start() || !redsq(point)
  defp c(z, m), do: if(rem(m, 4) == 0, do: z + 2, else: z - 2)

  def count(use, seen, possible, n, c, r, y) do
    case {possible, n} do
      {[], _} ->
        c

      {_, 0} ->
        if check(Enum.sort(MapSet.to_list(use)), y == r) do
          c + 1
        else
          c
        end

      {[p | possible], _} ->
        new = Enum.filter(neighs(p), &(!MapSet.member?(seen, &1)))
        use = MapSet.put(use, p)

        seen =
          Enum.reduce(new, seen, fn point, acc ->
            MapSet.put(acc, point)
          end)

        r = if redsq(p), do: r + 1, else: r
        y = if redsq(mirror(p)), do: y + 1, else: y
        n = n - 1

        if r + n < y,
          do: count(use, seen, possible, n, c, r, y),
          else: count(use, seen, new ++ possible, n, c, r, y)
    end
  end

  def translate(dx, dy, %Point{x: x, y: y}), do: Point.new(dx + x, dy + y)
  def rot(%Point{x: x, y: y}), do: Point.new(2 - y, x)

  def rot(points) do
    Enum.map(points, fn %Point{x: x, y: y} -> Point.new(2 - y, x) end)
  end

  def mirror(%Point{x: x, y: y}), do: Point.new(x, -y)

  def normalize(pol) do
    %Point{x: x, y: y} = Enum.find(pol, &redsq/1)
    Enum.map(pol, &translate(1 - x, 1 - y, &1))
  end

  def check(pol, cm) do
    rotated = Enum.take(Stream.iterate(pol, &rot/1), 4)
    mirrored = if cm, do: Enum.map(rotated, &mirror/1), else: []
    alts = Enum.map(rotated ++ mirrored, &normalize/1)
    Enum.all?(alts, &(&1 >= pol))
  end

  def f(0), do: 1
  def f(1), do: 2
  def f(2), do: 2
  def f(n), do: count(MapSet.new(), MapSet.new(), [start()], n, 0, 0, 0)

  def output(n) do
    IO.puts("#{n}: #{f(n)}")
  end

  def main(args \\ []) do
    case args do
      # Elixir has no lazy evaluation like Haskell, so we should limit the range.
      [] -> Enum.each(1..20, &output/1)
      [n] -> output(String.to_integer(n))
    end
  end
end

Polyominoes.main(System.argv())

在线试用!

haskell elixir
© www.soinside.com 2019 - 2024. All rights reserved.